package com.xbongbong.saas.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.i18n.util.I18nMessageUtil;
import com.xbongbong.paas.business.rule.RuleBusinessLogger;
import com.xbongbong.paas.constant.MessageConstant;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.constant.SizeConstant;
import com.xbongbong.paas.domain.entity.PaasAppEntity;
import com.xbongbong.paas.domain.entity.PaasFormDataEntity;
import com.xbongbong.paas.domain.entity.PaasFormExplainEntity;
import com.xbongbong.paas.domain.entity.ext.PaasFormDataEntityExt;
import com.xbongbong.paas.domain.entity.ext.PaasFormEntityExt;
import com.xbongbong.paas.elasticsearch.model.PaasEsModel;
import com.xbongbong.paas.elasticsearch.pojo.XbbAggregatedPage;
import com.xbongbong.paas.elasticsearch.util.EsHelper;
import com.xbongbong.paas.elasticsearch.util.EsUtil;
import com.xbongbong.paas.elasticsearch.util.XbbElasticsearchRestTemplate;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.enums.FlowStatusEnum;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.enums.PaymentSheetTypeEnum;
import com.xbongbong.paas.enums.PlatFormEnum;
import com.xbongbong.paas.enums.UnitEnum;
import com.xbongbong.paas.field.DefaultAttrPoJo;
import com.xbongbong.paas.field.FieldAttrEntity;
import com.xbongbong.paas.field.MultiUnitItemPoJo;
import com.xbongbong.paas.help.CommonHelp;
import com.xbongbong.paas.help.FormDataValidateProductHelp;
import com.xbongbong.paas.help.ProSaveHelp;
import com.xbongbong.paas.help.TransactionHelp;
import com.xbongbong.paas.help.UserHelp;
import com.xbongbong.paas.help.subform.TransferSubFormHelper;
import com.xbongbong.paas.log.MongoLogHelp;
import com.xbongbong.paas.log.pojo.InfoArrPojo;
import com.xbongbong.paas.model.PaasAppModel;
import com.xbongbong.paas.model.PaasFormExplainModel;
import com.xbongbong.paas.model.PaasFormModel;
import com.xbongbong.paas.pojo.AssociatedBusinessAfterSavePojo;
import com.xbongbong.paas.pojo.ButtonPojo;
import com.xbongbong.paas.pojo.FieldAttrEntityForImport;
import com.xbongbong.paas.pojo.FormTitlePoJo;
import com.xbongbong.paas.pojo.MultiUnitPricePoJo;
import com.xbongbong.paas.pojo.SummaryDataPoJo;
import com.xbongbong.paas.pojo.WorkFlowPojo;
import com.xbongbong.paas.pojo.dto.FormDataAddDTO;
import com.xbongbong.paas.pojo.dto.FormDataDeleteBatchDTO;
import com.xbongbong.paas.pojo.dto.FormDataListDTO;
import com.xbongbong.paas.pojo.dto.ImportFormDataDTO;
import com.xbongbong.paas.pojo.dto.PhysicalDeleteDTO;
import com.xbongbong.paas.pojo.dto.SaasFormSaveDTO;
import com.xbongbong.paas.pojo.dto.UserAndDepartmentGetDTO;
import com.xbongbong.paas.pojo.dto.ValidateDataDTO;
import com.xbongbong.paas.pojo.imports.CellTitlePojo;
import com.xbongbong.paas.pojo.imports.CellValuePojo;
import com.xbongbong.paas.pojo.imports.RowGroupPojo;
import com.xbongbong.paas.pojo.vo.FormDataAddVO;
import com.xbongbong.paas.pojo.vo.FormDataGetVO;
import com.xbongbong.paas.pojo.vo.UserAndDepartmentGetVO;
import com.xbongbong.paas.service.PaasAppService;
import com.xbongbong.paas.service.PaasFormDataService;
import com.xbongbong.parent.interfaces.DynamicStrategy;
import com.xbongbong.paas.service.dynamic.crm.strategy.DynamicStrategyFactory;
import com.xbongbong.paas.service.log.crm.help.OperationLogHelp;
import com.xbongbong.paas.service.team.TeamDataHelp;
import com.xbongbong.paas.service.workflow.trigger.WorkflowFormDataOperationService;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.helper.PageHelper;
import com.xbongbong.paas.toolbox.util.Arith;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.DateTimeUtil;
import com.xbongbong.paas.toolbox.util.JsonHelperUtil;
import com.xbongbong.paas.toolbox.util.PageHelperUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.paas.toolbox.wrap.UserVO;
import com.xbongbong.paas.util.ExplainUtil;
import com.xbongbong.parent.interfaces.logger.OperationLogFactory;
import com.xbongbong.parent.interfaces.logger.OperationLogHandle;
import com.xbongbong.pro.applist.pojo.AppListPojo;
import com.xbongbong.pro.applist.pojo.vo.ListAppVO;
import com.xbongbong.pro.businessdata.pojo.dto.FormatExplainDTO;
import com.xbongbong.pro.businessproduct.pojo.dto.BusinessProductListDTO;
import com.xbongbong.pro.businessproduct.pojo.vo.RefundAmountVO;
import com.xbongbong.pro.constant.BusinessConstant;
import com.xbongbong.pro.constant.ElasticConstant;
import com.xbongbong.pro.constant.I18nStringConstant;
import com.xbongbong.pro.contractperformance.pojo.dto.ContractPerformanceDeleteBatchDTO;
import com.xbongbong.pro.contractproduct.pojo.dto.ContractProductDeleteBatchDTO;
import com.xbongbong.pro.contractproduct.pojo.dto.ContractProductListDTO;
import com.xbongbong.pro.contractproduct.pojo.vo.ContractProductListVO;
import com.xbongbong.pro.customercommunicate.pojo.dto.CustomerDynamicAddDTO;
import com.xbongbong.pro.detailtab.dto.ChangeDocumentStatusSaveDTO;
import com.xbongbong.pro.detailtab.vo.ChangeDocumentStatusSaveVO;
import com.xbongbong.pro.detailtab.vo.ProductSummaryVO;
import com.xbongbong.pro.domain.entity.ReRollBackEntity;
import com.xbongbong.pro.domain.entity.UpdateDataEntity;
import com.xbongbong.pro.dynamic.pojo.dto.DynamicDeleteDTO;
import com.xbongbong.pro.dynamic.pojo.dto.DynamicSaveDTO;
import com.xbongbong.pro.enums.DistributorMarkEnum;
import com.xbongbong.pro.enums.RefundStatusEnum;
import com.xbongbong.pro.enums.SaasMarkEnum;
import com.xbongbong.pro.enums.errorcodes.BuinessDefaultErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.BusinessTypeErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.ContractErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.ProductErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.RefundErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.UserTeamErrorCodeEnum;
import com.xbongbong.pro.enums.permission.enums.ProPermissionAliasEnum;
import com.xbongbong.pro.enums.workflow.TriggerEventTypeEnum;
import com.xbongbong.pro.formdata.pojo.AfterSavePojo;
import com.xbongbong.pro.formdata.pojo.SaasNeedRedundantAttrPojo;
import com.xbongbong.pro.formdata.pojo.dto.SaasAnalysisDataDTO;
import com.xbongbong.pro.formexplain.pojo.dto.HandlerExplainDTO;
import com.xbongbong.pro.formexplain.pojo.dto.HandlerExplainInLinkItemDTO;
import com.xbongbong.pro.listbatch.pojo.dto.AddLabelDTO;
import com.xbongbong.pro.listbatch.pojo.dto.CancelDTO;
import com.xbongbong.pro.log.pojo.dto.DeleteBatchOperationLogDTO;
import com.xbongbong.pro.log.pojo.dto.DeleteOperationLogDTO;
import com.xbongbong.pro.log.pojo.dto.RuleBusinessLogDTO;
import com.xbongbong.pro.log.pojo.dto.UpdateBatchOperationLogDTO;
import com.xbongbong.pro.product.pojo.ProductSavePojo;
import com.xbongbong.pro.product.pojo.dto.FilterAttrOnOffJXCDTO;
import com.xbongbong.pro.product.pojo.dto.PagingProductDTO;
import com.xbongbong.pro.product.pojo.vo.DetailProductVO;
import com.xbongbong.pro.product.pojo.vo.PagingProductVO;
import com.xbongbong.pro.refund.pojo.dto.RefundDeleteBatchDTO;
import com.xbongbong.pro.refund.pojo.dto.RefundEditAttrUpdateDTO;
import com.xbongbong.pro.refund.pojo.dto.RefundUpdateBatchDTO;
import com.xbongbong.pro.refund.pojo.dto.RefundUpdateByBusinessRuleDTO;
import com.xbongbong.pro.refund.pojo.dto.RefundUpdateDTO;
import com.xbongbong.pro.refund.pojo.vo.RefundDeleteBatchVO;
import com.xbongbong.pro.refund.pojo.vo.RefundEditAttrUpdateVO;
import com.xbongbong.pro.refund.pojo.vo.RefundRedContractVO;
import com.xbongbong.pro.refund.pojo.vo.RefundUpdateBatchVO;
import com.xbongbong.pro.refunduser.pojo.dto.RefundUserDeleteBatchDTO;
import com.xbongbong.pro.service.toolbox.elasticsearch.help.ProEsHelper;
import com.xbongbong.pro.user.pojo.ReturnUserAndDepartmentPojo;
import com.xbongbong.saas.analytical.impl.RefundValidateAnalyticalServiceImpl;
import com.xbongbong.saas.annotation.BusinessTypeToServiceAnnotation;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.ErrorMessageConstant;
import com.xbongbong.saas.constant.ParameterConstant;
import com.xbongbong.saas.constant.ProductConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.domain.entity.ContractProductEntity;
import com.xbongbong.saas.domain.entity.InstockProductEntity;
import com.xbongbong.saas.domain.entity.OutstockProductEntity;
import com.xbongbong.saas.domain.entity.ProductSerialBalanceEntity;
import com.xbongbong.saas.domain.entity.ProductSerialFlowEntity;
import com.xbongbong.saas.domain.entity.RefundInvoiceEntity;
import com.xbongbong.saas.domain.entity.ext.ContractEntityExt;
import com.xbongbong.saas.domain.entity.ext.CustomerEntityExt;
import com.xbongbong.saas.domain.entity.ext.OutstockEntityExt;
import com.xbongbong.saas.domain.entity.ext.PaymentSheetEntityExt;
import com.xbongbong.saas.domain.entity.ext.ProductEntityExt;
import com.xbongbong.saas.domain.entity.ext.RefundEntityExt;
import com.xbongbong.saas.enums.BusinessProductEnum;
import com.xbongbong.saas.enums.BusinessTypeToServiceEnum;
import com.xbongbong.saas.enums.CompanyConfigEnum;
import com.xbongbong.saas.enums.ContractProductTypeEnum;
import com.xbongbong.saas.enums.InOutStockStatusEnum;
import com.xbongbong.saas.enums.InstockTypeEnum;
import com.xbongbong.saas.enums.OperateModuleTypeEnum;
import com.xbongbong.saas.enums.OperatePageEnum;
import com.xbongbong.saas.enums.OperateTypeEnum;
import com.xbongbong.saas.enums.OutstockTypeEnum;
import com.xbongbong.saas.enums.ProjectLogEnum;
import com.xbongbong.saas.enums.RedundantTemplateTypeEnum;
import com.xbongbong.saas.enums.RelativeProductEnum;
import com.xbongbong.saas.enums.SelectProductEnum;
import com.xbongbong.saas.enums.UpdateDataTypeEnum;
import com.xbongbong.saas.enums.XbbRefTypeEnum;
import com.xbongbong.saas.enums.business.ContractEnum;
import com.xbongbong.saas.enums.business.CustomerManagementEnum;
import com.xbongbong.saas.enums.business.InstockEnum;
import com.xbongbong.saas.enums.business.InvoiceEnum;
import com.xbongbong.saas.enums.business.OutstockEnum;
import com.xbongbong.saas.enums.business.PaymentEnum;
import com.xbongbong.saas.enums.business.PaymentSheetEnum;
import com.xbongbong.saas.enums.business.ProductEnum;
import com.xbongbong.saas.enums.business.RefundEnum;
import com.xbongbong.saas.enums.business.RefundInstockEnum;
import com.xbongbong.saas.enums.business.SerialEnum;
import com.xbongbong.saas.enums.business.SerialStatusEnum;
import com.xbongbong.saas.enums.dictionary.AllInBoundEnum;
import com.xbongbong.saas.enums.dictionary.DictionaryEnum;
import com.xbongbong.saas.enums.dictionary.EnableButtonEnum;
import com.xbongbong.saas.enums.dictionary.IsCancelEnum;
import com.xbongbong.saas.enums.dictionary.IsRedEnum;
import com.xbongbong.saas.enums.product.ContractProductEnum;
import com.xbongbong.saas.enums.product.RefundProductEnum;
import com.xbongbong.saas.enums.subform.ContractProductSubFormEnum;
import com.xbongbong.saas.help.BatchSeqExplainHelp;
import com.xbongbong.saas.help.DefaultAttrHelp;
import com.xbongbong.saas.help.ExplainHelp;
import com.xbongbong.saas.help.ImportHelper;
import com.xbongbong.saas.help.LogHandleHelp;
import com.xbongbong.saas.help.ProDetailHandlerHelp;
import com.xbongbong.saas.help.RefundHelp;
import com.xbongbong.saas.help.RelativeProductHelp;
import com.xbongbong.saas.help.SaasProductHelp;
import com.xbongbong.saas.help.SaasSaveHelp;
import com.xbongbong.saas.help.SaasUpdateHelp;
import com.xbongbong.saas.help.workflow.RefundSaveHelp;
import com.xbongbong.saas.model.ContractModel;
import com.xbongbong.saas.model.ContractProductModel;
import com.xbongbong.saas.model.CustomerModel;
import com.xbongbong.saas.model.DataDictionaryModel;
import com.xbongbong.saas.model.OutstockModel;
import com.xbongbong.saas.model.OutstockProductModel;
import com.xbongbong.saas.model.ProductModel;
import com.xbongbong.saas.model.ProductSerialBalanceModel;
import com.xbongbong.saas.model.ProductSerialFlowModel;
import com.xbongbong.saas.model.RefundInvoiceModel;
import com.xbongbong.saas.model.RefundModel;
import com.xbongbong.saas.model.SpecificationModel;
import com.xbongbong.saas.service.ContractPerformanceService;
import com.xbongbong.saas.service.ContractProductService;
import com.xbongbong.saas.service.ContractService;
import com.xbongbong.saas.service.CustomerCommunicateService;
import com.xbongbong.saas.service.FormatSpecialBusinessService;
import com.xbongbong.saas.service.InstockProductService;
import com.xbongbong.saas.service.ListBatchService;
import com.xbongbong.saas.service.MobileDetailService;
import com.xbongbong.saas.service.OutstockService;
import com.xbongbong.saas.service.ProductSerialService;
import com.xbongbong.saas.service.ProductService;
import com.xbongbong.saas.service.RefundService;
import com.xbongbong.saas.service.RefundUserService;
import com.xbongbong.saas.service.UserTeamService;
import com.xbongbong.saas.service.toolbox.help.LogHelp;
import com.xbongbong.saas.service.toolbox.help.UserTeamHelp;
import com.xbongbong.saas.toolbox.help.FastJsonHelper;
import com.xbongbong.sys.domain.entity.UserEntity;
import com.xbongbong.sys.model.UserModel;
import com.xbongbong.workflow.domain.entity.WorkflowEntity;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.TreeMap;
import java.util.stream.Collectors;

import static com.xbongbong.saas.toolbox.help.FastJsonHelper.getDoubleFromFormData;
import static com.xbongbong.saas.toolbox.help.FastJsonHelper.getDoubleOrDefaultFromFormData;
import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
import static org.elasticsearch.index.query.QueryBuilders.termsQuery;

/**
 * @author feng.zheng
 * @version v1.0
 * @date 2019/3/22 15:28
 * @since v1.0
 */
@Service("refundService")
@BusinessTypeToServiceAnnotation(businessService = BusinessTypeToServiceEnum.REFUND)
public class RefundServiceImpl implements RefundService, FormatSpecialBusinessService {

    private static final Logger LOG = LoggerFactory.getLogger(RefundServiceImpl.class);

    @Resource
    private SaasSaveHelp saasSaveHelp;
    @Resource
    private SaasUpdateHelp saasUpdateHelp;
    @Resource
    private ContractModel contractModel;
    @Resource
    private ProductModel productModel;
    @Resource
    private RefundModel refundModel;
    @Resource
    private ContractProductModel contractProductModel;
    @Resource
    private PaasFormExplainModel paasFormExplainModel;
    @Resource
    private RefundInvoiceModel refundInvoiceModel;
    @Resource
    private UserTeamService userTeamService;
    @Resource
    private CustomerModel customerModel;
    @Resource
    private ExplainHelp explainHelp;
    @Resource
    private SpecificationModel specificationModel;
    @Resource
    private UserModel userModel;
    @Resource
    private ContractService contractService;
    @Resource
    private ProductService productService;
    @Resource
    private PaasFormDataService paasFormDataService;
    @Resource
    private PaasEsModel paasEsModel;
    @Resource
    private RefundUserService refundUserService;
    @Resource
    private EsHelper esHelper;
    @Resource
    private ContractPerformanceService contractPerformanceService;
    @Resource
    private ContractProductService contractProductService;
    @Resource
    private OutstockProductModel outstockProductModel;
    @Resource
    private PaasAppModel paasAppModel;
    @Resource
    private UserHelp userHelp;
    @Resource
    private ProEsHelper proEsHelper;
    @Resource
    private ImportHelper importHelper;
    @Resource
    @Lazy
    private CustomerCommunicateService customerCommunicateService;
    @Resource
    private DataDictionaryModel dataDictionaryModel;
    @Resource
    private MongoLogHelp mongoLogHelp;
    @Resource
    @Lazy
    private RuleBusinessLogger ruleBusinessLogger;
    @Resource
    private ListBatchService listBatchService;
    @Resource
    private XbbElasticsearchRestTemplate xbbElasticsearchRestTemplate;
    @Resource
    private FormDataValidateProductHelp formDataValidateProductHelp;
    @Resource
    private OutstockService outstockService;
    @Resource
    private MobileDetailService mobileDetailService;
    @Resource
    private ProDetailHandlerHelp proDetailHandlerHelp;
    @Resource
    private PaasAppService paasAppService;
    @Resource
    private OutstockModel outstockModel;
    @Resource
    private ProductSerialFlowModel productSerialFlowModel;
    @Resource
    private ProductSerialBalanceModel productSerialBalanceModel;
    @Resource
    private ProductSerialService productSerialService;
    @Resource
    private TransferSubFormHelper transferSubFormHelper;
    @Resource
    private InstockProductService instockProductService;
    @Resource
    private DefaultAttrHelp defaultAttrHelp;
    @Resource
    private RelativeProductHelp relativeProductHelp;
    @Resource
    private LogHelp logHelp;
    @Resource
    private LogHandleHelp logHandleHelp;
    @Resource
    private RefundValidateAnalyticalServiceImpl refundAnalyticalService;
    @Resource
    private RefundSaveHelp refundSaveHelp;
    @Resource
    private RefundHelp refundHelp;
    @Resource
    private TeamDataHelp teamDataHelp;
    @Resource
    private UserTeamHelp userTeamHelp;

    @Resource
    private OperationLogFactory operationLogFactory;
    @Resource
    private DynamicStrategyFactory dynamicStrategyFactory;
    @Resource
    private WorkflowFormDataOperationService workflowFormDataOperationService;
    @Resource
    private CommonHelp commonHelp;
    @Resource
    private PaasFormModel paasFormModel;
    @Resource
    private TransactionHelp transactionHelp;

    /**
     * 判断进销存是否开启
     *
     * @param corpid 公司Id
     * @return boolean true:开启进销存。false：关闭进销存
     * @author youli.chen
     * @date 2019/3/7 8:50
     * @since v1.0
     */
    @Override
    public boolean ifJXCOpen(String corpid) throws XbbException {
        PaasAppEntity paasAppEntity = paasAppModel.getByAlias(XbbRefTypeEnum.JXC.getAlias(), corpid);
        Integer enable;
        if (paasAppEntity == null) {
            LOG.error("RefundServiceImpl 该公司进销存业务没有数据" + corpid);
            // 默认关闭
            enable = BasicConstant.ZERO;
        } else {
            enable = paasAppEntity.getEnable();
        }
        return Objects.equals(BasicConstant.ONE, enable);
    }

    /**
     * 保存前saas特殊校验
     *
     * @param validateDataDTO saas特殊校验数据入参
     * @throws XbbException 业务异常
     * @author feng.zheng
     * @date 2019/1/18
     */
    @Override
    public void beforeSave(ValidateDataDTO validateDataDTO) throws XbbException {
        refundAnalyticalService.beforeSave(validateDataDTO);
    }



    /**
     * 保存后逻辑
     *
     * @param saasFormSaveDTO saas保存数据
     * @param associatedBusinessAfterSavePojo 关联新建信息
     * @throws XbbException 业务异常
     * @author feng.zheng
     */
    @Override
    public AfterSavePojo afterSave(SaasFormSaveDTO saasFormSaveDTO, AssociatedBusinessAfterSavePojo associatedBusinessAfterSavePojo) throws XbbException {
        AfterSavePojo afterSavePojo = new AfterSavePojo();
        PaasFormDataEntity newPaasFormDataEntity = saasFormSaveDTO.getNewPaasFormDataEntity();

        RefundEntityExt newRefundEntityExt = new RefundEntityExt();
        BeanUtil.copyProperties(newPaasFormDataEntity, newRefundEntityExt);

        JSONObject newData = saasFormSaveDTO.getNewData();
        String corpid = saasFormSaveDTO.getCorpid();
        Boolean isNew = saasFormSaveDTO.getIsNew();
        // todo 审批
        Long customerId = FastJsonHelper.getLongOrDefaultFromFormData(newData, RefundEnum.CUSTOMER_ID.getAttr(), 0L);

        Long contractId = FastJsonHelper.getLongOrDefaultFromFormData(newData, RefundEnum.CONTRACT_ID.getAttr(), 0L);

        Double returnAmount = getDoubleOrDefaultFromFormData(newData, RefundEnum.RETURN_AMOUNT.getAttr(), 0D);
        RefundRedContractVO refundRedContractVO = null;
        try {
            ContractEntityExt contractEntityExt = contractModel.getByKey(contractId, corpid);
            if (isNew) {
                //ContractEntityExt redContractEntity = generateRedContract(newPaasFormDataEntity, contractEntityExt, returnAmount, saasFormSaveDTO.getSaasNeedRedundantAttrPoJo().getProductArray(), FlowStatusEnum.NOT_NEED_APPROVAL.getType());
                //JSONArray invoiceIdArray = FastJsonHelper.getJsonArrOrDefaultFromFormData(newData, RefundEnum.INVOICES.getAttr(), jsonArray);
                refundRedContractVO = generateRedContract(newPaasFormDataEntity, contractEntityExt, returnAmount, saasFormSaveDTO.getNewData().getJSONArray(RefundEnum.PRODUCTS.getAttr()), FlowStatusEnum.NOT_NEED_APPROVAL.getType(), saasFormSaveDTO.getIsNew(), saasFormSaveDTO.getLoginUser());
                ContractEntityExt redContractEntity = refundRedContractVO.getContractEntityExt();
                Long redContractId = redContractEntity.getId();
                //TODO 新建关联回款单和发票做异步处理，新建红冲合同步骤也可以走异步，业务逻辑需要开发负责人确认
//            Runnable runnable = () -> {
//                try {
                    ReRollBackEntity reRollBackEntity = associatedBusinessAfterSavePojo.getReRollBackEntity();
                    List<Long> redPaymentSheetIds = generateRedPayment(redContractEntity, associatedBusinessAfterSavePojo.getSheetArray(), saasFormSaveDTO);
                    reRollBackEntity.setRedSheetId(redPaymentSheetIds);
                    List<Long> redPaymentIds = generateRedPaymentPlan(redContractEntity, associatedBusinessAfterSavePojo.getPaymentArray(), saasFormSaveDTO);
                    reRollBackEntity.setRedPaymentId(redPaymentIds);
                    // --关联发票红冲/作废--*/
                    List<Long> invoiceIds = saveRefundInvoice(saasFormSaveDTO, associatedBusinessAfterSavePojo.getInvoiceArray(), redContractId, FlowStatusEnum.NOT_NEED_APPROVAL.getType());
                    reRollBackEntity.setRedInvoiceId(invoiceIds);
                    JSONObject refundData = newPaasFormDataEntity.getData();
                    // 更新退货退款中关联发票和关联红冲回款单字段内容（红冲发票和红冲回款单属于新建，其id在新建成功后才能拿到）
                    if (!invoiceIds.isEmpty()) {
                        refundData.put(RefundEnum.INVOICES.getAttr(), invoiceIds);
                    } else {
                        refundData.put(RefundEnum.INVOICES.getAttr(), null);
                        refundData.put(RefundEnum.INVOICES_LINKED_TEXT.getAttr(), null);
                    }
                    if (!redPaymentSheetIds.isEmpty()) {
                        refundData.put(RefundEnum.PAYMENT_SHEETS.getAttr(), redPaymentSheetIds);
                        if (associatedBusinessAfterSavePojo.getRefundAmount() != null) {
                            refundData.put(RefundEnum.REFUND_AMOUNT.getAttr(), associatedBusinessAfterSavePojo.getRefundAmount());
                        }
                    } else {
                        refundData.put(RefundEnum.PAYMENT_SHEETS.getAttr(), null);
                        refundData.put(RefundEnum.PAYMENT_SHEETS_LINKED_TEXT.getAttr(), null);
                    }
                    //应收款无审批
                    if (!redPaymentIds.isEmpty()) {
                        refundData.put(RefundEnum.PAYMENTS.getAttr(), redPaymentIds);
                    } else {
                        refundData.put(RefundEnum.PAYMENTS.getAttr(), null);
                        refundData.put(RefundEnum.PAYMENTS_LINKED_TEXT.getAttr(), null);
                    }
                    newPaasFormDataEntity.setData(refundData);
                    RefundEntityExt refundEntityExt = new RefundEntityExt();
                    BeanUtils.copyProperties(newPaasFormDataEntity, refundEntityExt);
                    // TODO: 2020/11/4 不更新子表单
                    refundModel.save(refundEntityExt, false);
                // 动态
                try {
                    if (Objects.equals(DistributorMarkEnum.DISTRIBUTOR.getCode(), saasFormSaveDTO.getDistributorMark())) {
                        // 项目日志
                        String creatorId = newPaasFormDataEntity.getCreatorId();
                        UserEntity creatorUser = userModel.getByKeyIngoreDel(creatorId, corpid);
                        String customerName = FastJsonHelper.getStringOrDefaultFromFormData(newData, RefundEnum.CUSTOMER_ID_LINKED_TEXT.getAttr(), "");
                        String refundReason = FastJsonHelper.getStringFromFormData(newData, RefundEnum.REFUND_REASON.getAttr());
                        String communicateMemo = creatorUser.getName() + I18nMessageUtil.getMessage(I18nStringConstant.CREATE_REFUND);
                        if (!StringUtil.isEmpty(refundReason)) {
                            //获取启用的退货原因
                            Map<String, String> refundReasonMap = dataDictionaryModel.getDictionaryMap4Saas(DictionaryEnum.REFUND_REASON, corpid, newPaasFormDataEntity.getFormId());
                            String refundReasonStr = refundReasonMap.get(refundReason) == null ? "" : refundReasonMap.get(refundReason);
                            if (!StringUtil.isEmpty(refundReasonStr)) {
                                communicateMemo += "，" + RefundEnum.REFUND_REASON.getAttrName() + ": " + refundReasonStr;
                            }
                        }
                        CustomerDynamicAddDTO customerDynamicAddDTO = new CustomerDynamicAddDTO();
                        customerDynamicAddDTO.setCorpid(corpid);
                        customerDynamicAddDTO.setUserId(creatorId);
                        customerDynamicAddDTO.setCustomerId(customerId);
                        customerDynamicAddDTO.setCustomerName(customerName);
                        customerDynamicAddDTO.setMemo(communicateMemo);
                        customerDynamicAddDTO.setCommunicateBusinessText(newPaasFormDataEntity.getSerialNo());
                        customerDynamicAddDTO.setCommunicateBusinessType(XbbRefTypeEnum.REFUND.getCode());
                        customerDynamicAddDTO.setDataId(newPaasFormDataEntity.getId());
                        customerDynamicAddDTO.setLogType(ProjectLogEnum.REFUND_CREATE.getSubType());
                        customerDynamicAddDTO.setDistributorMark(DistributorMarkEnum.DISTRIBUTOR.getCode());
                        customerCommunicateService.addCustomerDynamic(customerDynamicAddDTO);
                    } else {
                        DynamicStrategy dynamicStrategy = dynamicStrategyFactory.getDynamicStrategyByBusinessType(saasFormSaveDTO.getBusinessType());
                        transactionHelp.afterCommitOrCommitNow(p -> {
                            dynamicStrategy.save(DynamicSaveDTO.initDynamicSaveDTO(newPaasFormDataEntity.getId(), newPaasFormDataEntity.getFormId(), saasFormSaveDTO, userModel.getByKeyIngoreDel(newPaasFormDataEntity.getCreatorId(), corpid), null));
                        });
                    }
                } catch (Exception e) {
                    LOG.error("退货退款创建动态失败：", e);
                }
//                } catch (Exception e) {
//                    LOG.error("退货退款afterSave方法报错", e);
//                }
//            };
//            threadPoolBeanConfig.addUpdateDelThreadPool().execute(runnable);
            } else {
                // 更新退货产品
                Map<Long, Double> changeNumMap = setRefundProducts(newRefundEntityExt);
                JSONArray jsonArray = newRefundEntityExt.getData().getJSONArray(RefundEnum.PRODUCTS.getAttr());
                List<Long> refList = new ArrayList<>();
                Map<Long, Double> refNumMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                if (Objects.nonNull(jsonArray)) {
                    for (int i = 0; i < jsonArray.size(); i++) {
                        JSONObject jsonObject = jsonArray.getJSONObject(i);
                        // 上游单据，原合同产品表ID
                        Long refProductId = FastJsonHelper.getLongFromFormData(jsonObject, ContractProductSubFormEnum.REF_PRODUCT_ID.getDataAttr());
                        if (Objects.nonNull(refProductId)) {
                            refList.add(refProductId);
                            refNumMap.put(refProductId, changeNumMap.getOrDefault(refProductId, getDoubleFromFormData(jsonObject, ContractProductEnum.NUM.getAttr())));
                        }
                    }
                    // 原先的产品变化
                    Iterator iterator = changeNumMap.keySet().iterator();
                    while (iterator.hasNext()) {
                        Long contractProductId = (Long) iterator.next();
                        Double changeNum = changeNumMap.get(contractProductId);
                        if (!refList.contains(contractProductId)) {
                            refList.add(contractProductId);
                            refNumMap.put(contractProductId, changeNum);
                        }
                    }
                }
                if (!refList.isEmpty()) {
                    boolean ifJXCOpen = ifJXCOpen(corpid);
                    List<ContractProductEntity> contractProductEntityList = contractProductModel.getContractProductByContractIdIn(corpid, Collections.singletonList(contractId));

                    if (ifJXCOpen) {
                        JSONObject contractData = contractEntityExt.getData();
                        List<Long> outstockIds = FastJsonHelper.getJsonArrOrDefaultFromFormData(contractData, ContractEnum.OUTSTOCK_ID.getAttr(), new JSONArray()).toJavaList(Long.class);
                        // 未出库就不执行
                        if (!outstockIds.isEmpty()) {
                            // 处理出库产品表和原合同产品表
                            Map<String, Object> params = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                            params.put("corpid", corpid);
                            params.put("outstockIdIn", outstockIds);
                            params.put("del", DelEnum.NORMAL.getDel());
                            List<OutstockProductEntity> outstockProductEntities = outstockProductModel.findEntitys(params);
                            Map<Long, Double> refNumsMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                            for (OutstockProductEntity item : outstockProductEntities) {
                                // 销售出库产品表，上游单据合同ID
                                if (refNumMap.containsKey(item.getId())) {
                                    item.setInstockNum(Arith.add(item.getInstockNum() == null ? 0D : item.getInstockNum(), refNumMap.get(item.getId())));
                                    refNumsMap.put(item.getRefProductId(), Arith.add(refNumMap.get(item.getId()), refNumsMap.getOrDefault(item.getRefProductId(), 0D)));
                                }
                            }
                            outstockProductModel.updateBatch(outstockProductEntities, corpid);
                            if (!refNumsMap.isEmpty()) {
                                for (ContractProductEntity item : contractProductEntityList) {
                                    Double instockNum = item.getInstockNum() == null ? 0D : item.getInstockNum();
                                    if (refNumsMap.containsKey(item.getId())) {
                                        item.setInstockNum(Arith.add(instockNum, refNumsMap.getOrDefault(item.getId(), 0D)));
                                    }
                                }
                                contractProductModel.updateBatch(contractProductEntityList, corpid);
                            }
                        }
                    } else {
                        // 处理原合同产品表
                    /*Map<String, Object> params = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    params.put("corpid", corpid);
                    params.put("idIn", refList);
                    params.put("del", DelEnum.NORMAL.getDel());
                    List<ContractProductEntity> contractProductEntities = contractProductModel.findEntitys(params);*/
                        contractProductEntityList.forEach(item -> {
                            if (refNumMap.containsKey(item.getId())) {
                                item.setInstockNum(Arith.add(item.getInstockNum(), refNumMap.get(item.getId())));
                            }
                        });
                        contractProductModel.updateBatch(contractProductEntityList, corpid);
                    }
                }

                Long redContractId = FastJsonHelper.getLongOrDefaultFromFormData(newRefundEntityExt.getData(), RefundEnum.RED_CONTRACT_ID.getAttr(), 0L);
                ContractEntityExt redContractEntity = contractModel.getByKey(redContractId, corpid);
                // 更新红冲合同的合同成本，合同毛利，现金毛利(包含新建和编辑)
                if (Objects.nonNull(redContractEntity) && Objects.equals(0, redContractEntity.getDel())) {
                    redContractEntity.setFlowStatus(newRefundEntityExt.getFlowStatus());
                    updateRedContract(jsonArray, corpid, redContractEntity, contractEntityExt, newRefundEntityExt.getData(), returnAmount, isNew, newRefundEntityExt.getId());
                } else {
                    LOG.warn("redContractEntity no have， dataId+" + redContractId + "；corpid=" + corpid);
                    throw new XbbException(ContractErrorCodeEnum.API_ERROR_203025);
                }
            }

            // 团队保存
            afterSavePojo = teamDataHelp.saveUserTeam(saasFormSaveDTO.getSaasNeedRedundantAttrPoJo(), saasFormSaveDTO.getNewPaasFormDataEntity().getId(), newPaasFormDataEntity, saasFormSaveDTO.getIsImport(), false);
//        userTeamService.saveUserTeam(saasFormSaveDTO);
        }catch (Exception e){
            // 这里做个回滚操作，不然会出现红冲合同es有，数据库没有的脏数据
            rollbackRedContract(isNew,corpid,refundRedContractVO);
            LOG.error("退货退款afterSave出现异常",e);
            throw e;
        }
    return afterSavePojo;
    }

    /**
     * 回滚红冲合同 防止出现es有数据，数据库没数据
     * date: 2022/10/13 6:47 下午
     * @author yingjf
     * @param isNew: 新建   新建才回滚
     * @param corpid: 公司id
     * @param refundRedContractVO:
     */
    private void rollbackRedContract(Boolean isNew,String corpid,RefundRedContractVO refundRedContractVO) throws XbbException{
        if (isNew && refundRedContractVO!=null){
            ContractEntityExt contractEntityExt = refundRedContractVO.getContractEntityExt();
            Long id = contractEntityExt.getId();
            PhysicalDeleteDTO physicalDeleteDTO = new PhysicalDeleteDTO();
            physicalDeleteDTO.setEsId(corpid + "_" + id);
            physicalDeleteDTO.setIndex(IndexTypeEnum.IDX_SAAS_CONTRACT.getIndex());
            physicalDeleteDTO.setType(IndexTypeEnum.IDX_SAAS_CONTRACT.getType());
            paasEsModel.physicalDelete(physicalDeleteDTO);
        }
    }

    /**
     * 更新退货单产品
     *
     * @param newRefundEntityExt     前端传入的数据
     * @author youli.chen
     * @date  2019/2/21 22:01
     */
    public Map<Long, Double> setRefundProducts(RefundEntityExt newRefundEntityExt) throws XbbException {
        String corpid = newRefundEntityExt.getCorpid();
        JSONObject refundData = newRefundEntityExt.getData();

        Long redContractId = FastJsonHelper.getLongOrDefaultFromFormData(refundData, RefundEnum.RED_CONTRACT_ID.getAttr(), 0L);
        JSONArray productArray = refundData.getJSONArray(RefundEnum.PRODUCTS.getAttr());

        Map<String, Object> modelMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        modelMap.put("corpid", corpid);
        modelMap.put("contractId", redContractId);
        modelMap.put("del", DelEnum.NORMAL.getDel());
        List<ContractProductEntity> contractProductEntityList = contractProductModel.findEntitys(modelMap);
        Map<Long, ContractProductEntity> orginProductMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);

        contractProductEntityList.forEach(item -> orginProductMap.put(item.getId(), item));
        Map<Long, ContractProductEntity> orginProductMapCopy = new HashMap<>(orginProductMap);
        List<ContractProductEntity> productAddList = new ArrayList<>();
        List<ContractProductEntity> productUpdateList = new ArrayList<>();
        Map<Long, PaasFormDataEntityExt> productMap = formDataValidateProductHelp.product2saveMap(corpid,productArray);
        Integer sort = 0;
        Map<Long, Double> changeNumMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);

        for (int i = 0; i < productArray.size(); i++) {
            JSONObject jsonObject = productArray.getJSONObject(i);
            Long pageProductId = jsonObject.getLong(SelectProductEnum.PRODUCT.getAttr());
            Long businessProductId = jsonObject.getLong(BusinessConstant.PRODUCT_SUB_ID);
            sort++;
            Double productNum = jsonObject.getDouble(ContractProductEnum.NUM.getAttr());
            boolean addProductFlag = formDataValidateProductHelp.addProductFlag(businessProductId);
            ContractProductEntity contractProductEntity;
            Double originNum = 0D;
            if (addProductFlag) {
                //新增产品
                contractProductEntity = new ContractProductEntity();
                productAddList.add(contractProductEntity);
            } else if (orginProductMap.containsKey(businessProductId)) {
                //编辑产品
                contractProductEntity = orginProductMap.get(businessProductId);
                productUpdateList.add(contractProductEntity);
                originNum = Math.abs(contractProductEntity.getProductNum());
                //只剩删除的产品
                orginProductMap.remove(businessProductId);
            } else {
                //删除产品
                continue;
            }
            JSONObject productData = productMap.get(pageProductId).getData();
            contractProductEntity.setCorpid(corpid);
            contractProductEntity.setContractId(redContractId);
            contractProductEntity.setParentId(productData.getLong(ProductEnum.PARENT_ID.getAttr()));
            contractProductEntity.setProductId(pageProductId);
            contractProductEntity.setProductNum(-productNum);
            contractProductEntity.setProductName(productData.getString(ProductEnum.NAME.getAttr()));
            contractProductEntity.setProductNo(productData.getString(ProductEnum.PRODUCT_NO.getAttr()));
            Double price = jsonObject.getDouble(RefundProductEnum.PRICE.getAttr());
            price = price != null ? price : 0D;
            contractProductEntity.setPrice(price);
            Integer enableMultiUnit = productData.getInteger(ProductEnum.ENABLE_MULTI_UNIT.getAttr());
            if (Objects.equals(enableMultiUnit, 1)) {
                formDataValidateProductHelp.setBusinessUnit(jsonObject, contractProductEntity);
                contractProductEntity.setProductUnit(jsonObject.getString(SelectProductEnum.UNIT.getAttr()));
            } else {
                contractProductEntity.setProductUnit(productData.getString(ProductEnum.UNIT.getAttr()));
                jsonObject.put(SelectProductEnum.UNIT.getAttr(),productData.getString(ProductEnum.UNIT.getAttr()));
            }
            // contractProductEntity.setProductUnit(productData.getString(ProductEnum.UNIT.getAttr()));
            // 折扣：默认为100%
            Double discount = jsonObject.getDouble(ContractProductEnum.DISCOUNT.getAttr());
            discount = discount == null ? 100 : discount;
            contractProductEntity.setDiscount(discount);
            contractProductEntity.setSpecification(productData.getString(ProductEnum.SPECIFICATION_LINK_TEXT.getAttr()));
            contractProductEntity.setContractOutstockNum(0D);
            contractProductEntity.setInstockNum(0D);
            // 备注
            String memo = jsonObject.getString(ContractProductEnum.MEMO.getAttr());
            contractProductEntity.setMemo(memo);
            contractProductEntity.setBarcode(productData.getString(ProductEnum.BARCODE.getAttr()));
            contractProductEntity.setCost(jsonObject.getDouble(SelectProductEnum.COST.getAttr()));
            contractProductEntity.setHistoricalPrice(productData.getDouble(ProductEnum.PRICE.getAttr()));
            contractProductEntity.setSort(sort);
            JSONArray imgArr = FastJsonHelper.getJsonArrFromFormData(productData, ProductEnum.PRODUCT_IMGS.getAttr());
            if (Objects.isNull(imgArr) || imgArr.isEmpty()) {
                imgArr = FastJsonHelper.getJsonArrFromFormData(productData, ProductEnum.THUMBNAIL.getAttr());
            } else {
                imgArr = JSONArray.parseArray(JSON.toJSONString(imgArr.subList(0, 1)));
            }
            contractProductEntity.setProductThumbnail(imgArr.toJSONString());
            contractProductEntity.setType(ContractProductTypeEnum.REFUND.getCode());
            jsonObject.put(ContractProductEnum.UNIT.getAttr(),productData.getString(ProductEnum.UNIT.getAttr()));
            contractProductEntity.setData(jsonObject);
            if (Objects.nonNull(jsonObject.getLong(BusinessConstant.PRODUCT_SUB_ID))) {
//                contractProductEntity.setRefProductId(jsonObject.getLong(BusinessConstant.PRODUCT_SUB_ID));
                long temp = jsonObject.getLong(BusinessConstant.PRODUCT_SUB_ID);
//                ContractProductEntity contractProductModelByKey = contractProductModel.getByKey(temp, corpid);
                ContractProductEntity entity = orginProductMapCopy.get(temp);
                if(entity!=null){
                    Long refProductId = entity.getRefProductId();
                    changeNumMap.put(refProductId, Arith.sub(productNum, originNum));
                }
            }
            if(jsonObject.get(BusinessConstant.REF_PRODUCT_ID)!=null){
                long refProductId = jsonObject.getLong(BusinessConstant.REF_PRODUCT_ID);
                if(!changeNumMap.containsKey(refProductId)){
                    contractProductEntity.setRefProductId(refProductId);
                    changeNumMap.put(refProductId, Arith.sub(productNum, originNum));
                }
            }
        }

        if(!productUpdateList.isEmpty()){
            for (ContractProductEntity updateProduct : productUpdateList) {
                JSONObject jsonObject = updateProduct.getData();
                if (Objects.nonNull(jsonObject)){
                    jsonObject.remove(ProductConstant.SEQ);
                    jsonObject.remove(ProductEnum.ENABLE_SERIAL_NUMBER.getSaasAttr());
                    jsonObject.remove(ProductEnum.ENABLE_BATCH_SHELF_LIFE.getSaasAttr());
                }
                contractProductModel.update(updateProduct);
            }
        }
        if(!orginProductMap.isEmpty()){
            for (Map.Entry<Long, ContractProductEntity> entry : orginProductMap.entrySet()) {
                ContractProductEntity delProduct = entry.getValue();
                changeNumMap.put(delProduct.getRefProductId(), Arith.sub(0D, Math.abs(delProduct.getProductNum())));
                // 删除产品时，更新序列号结存记录，删除序列号流水记录
                updateSerial(delProduct);
                contractProductModel.deleteByKey(delProduct.getId(), delProduct.getCorpid());
            }
        }
        if(!productAddList.isEmpty()){
            for (ContractProductEntity addProduct : productAddList) {
                JSONObject productData = addProduct.getData();
                JSONArray seqArray = productData.getJSONArray(ProductConstant.SEQ);
                int enableSerialNumber = productData.getIntValue(ProductEnum.ENABLE_SERIAL_NUMBER.getSaasAttr());
                // 移除序列号相关数据，不存入关联产品数据中
                productData.remove(ProductConstant.SEQ);
                productData.remove(ProductEnum.ENABLE_SERIAL_NUMBER.getSaasAttr());
                productData.remove(ProductEnum.ENABLE_BATCH_SHELF_LIFE.getSaasAttr());

                contractProductModel.insert(addProduct);
                // 新增序列号，关联产品不保存序列号，但是后面序列号保存以及生成出入库单需要序列号数据，所以给他加回去
                if (Objects.nonNull(seqArray) && !seqArray.isEmpty()) {
                    productData.put(ProductConstant.SEQ, seqArray);
                    productData.put(ProductEnum.ENABLE_SERIAL_NUMBER.getSaasAttr(), enableSerialNumber);
                }
                JSONArray jsonArray = new JSONArray();
                jsonArray.add(productData);
                saveSerial(newRefundEntityExt, jsonArray);
            }
        }
        return changeNumMap;
    }

    private void updateSerial(ContractProductEntity delProduct) throws XbbException {
        productSerialFlowModel.delByRefProductAndBusinessType(delProduct.getCorpid(), delProduct.getId(), XbbRefTypeEnum.REFUND.getCode());

        List<ProductSerialBalanceEntity> balanceEntities = productSerialBalanceModel.getByRefProductId(delProduct.getId(), XbbRefTypeEnum.REFUND.getCode(), delProduct.getCorpid());
        if (Objects.nonNull(balanceEntities)) {
            for (ProductSerialBalanceEntity entity : balanceEntities) {
                String seqKey = entity.getSeqKey();

                ProductSerialFlowEntity lastSerialFlow = productSerialFlowModel.getLastSerialFlow(delProduct.getCorpid(), seqKey, entity.getRefId());
                entity.setRefId(lastSerialFlow.getRefId());
                entity.setBusinessType(lastSerialFlow.getBusinessType());
                entity.setRefProductId(lastSerialFlow.getRefProductId());
                entity.setAddTime(lastSerialFlow.getAddTime());
                entity.setUpdateTime(lastSerialFlow.getUpdateTime());
                entity.setDate(lastSerialFlow.getDate());
                entity.setWarehouseId(lastSerialFlow.getWarehouseId());
                productSerialBalanceModel.update(entity);
            }
        }
    }

    public List<Long> saveRefundInvoice(SaasFormSaveDTO saasFormSaveDTO, JSONArray invoiceArray, Long redContractId, Integer flowStatus) throws XbbException {
        Long now = DateTimeUtil.getInt();
        PaasFormDataEntity newPaasFormDataEntity = saasFormSaveDTO.getNewPaasFormDataEntity();
        String corpid = saasFormSaveDTO.getCorpid();
        Long refundId = newPaasFormDataEntity.getId();
        List<Long> invoiceIds = new ArrayList<>();
        if (Objects.isNull(redContractId) || Objects.isNull(invoiceArray)) {
            return invoiceIds;
        }
        //关联作废/红冲发票处理
        List<Long> cancelInvoiceIds = new ArrayList<>();
        for(Object obj : invoiceArray){
            JSONObject invoiceJsonObject = (JSONObject)obj;
            String refundCreatorId = saasFormSaveDTO.getNewPaasFormDataEntity().getCreatorId();
            if (refundCreatorId != null) {
                invoiceJsonObject.put(StringConstant.CREATOR_ID, refundCreatorId);
            }
            PaasFormDataEntity invoiceEntity = handleInvoiceWebPlatformLinkAddData(invoiceJsonObject);
            JSONObject invoiceData = invoiceEntity.getData();
            Integer isCancel = invoiceData.getInteger(InvoiceEnum.IS_CANCEL.getAttr());
            Integer isRed = invoiceData.getInteger(InvoiceEnum.IS_RED.getAttr());
            Long invoiceId = invoiceEntity.getId();
            if(Objects.equals(IsCancelEnum.IS_CANCEL.getCode(), isCancel)){
                cancelInvoiceIds.add(invoiceEntity.getId());
            }
            if(Objects.equals(IsRedEnum.RED.getCode(), isRed)){
                //关联红冲发票新建
                FormDataAddDTO formDataAddDTO = new FormDataAddDTO();
                BeanUtil.copyProperties(invoiceEntity, formDataAddDTO);
                BeanUtil.copyProperties(saasFormSaveDTO, formDataAddDTO);
                JSONObject data = invoiceEntity.getData();
                invoiceAmountDetailHandle(data);
                formDataAddDTO.setDataList(data);
                formDataAddDTO.setBusinessType(XbbRefTypeEnum.INVOICE.getCode());
                formDataAddDTO.setSubBusinessType(XbbRefTypeEnum.INVOICE.getCode());
                formDataAddDTO.setSaasMark(SaasMarkEnum.SAAS.getCode());
                SaasNeedRedundantAttrPojo saasNeedRedundantAttrPojo = new SaasNeedRedundantAttrPojo();
                saasNeedRedundantAttrPojo.setRefundId(saasFormSaveDTO.getNewPaasFormDataEntity().getId());
                formDataAddDTO.setSaasNeedRedundantAttrPoJo(saasNeedRedundantAttrPojo);
                FormDataAddVO formDataAddVO = paasFormDataService.add(formDataAddDTO);
                //发票如果开启流程，返回的发票为空
                invoiceId = formDataAddVO.getDataId();
            }
            if (invoiceId != null) {
                RefundInvoiceEntity refundInvoiceEntity = new RefundInvoiceEntity();
                refundInvoiceEntity.setRefundId(refundId);
                refundInvoiceEntity.setCorpid(corpid);
                refundInvoiceEntity.setDel(DelEnum.NORMAL.getDel());
                refundInvoiceEntity.setAddTime(now);
                refundInvoiceEntity.setUpdateTime(now);
                refundInvoiceEntity.setInvoiceId(invoiceId);
                refundInvoiceEntity.setRedContractId(redContractId);
                refundInvoiceEntity.setRedPaymentId(0L);
                refundInvoiceEntity.setFlowStatus(flowStatus);
                refundInvoiceModel.save(refundInvoiceEntity);
                invoiceIds.add(invoiceId);
            }
        }
        // 关联作废发票
        if (!cancelInvoiceIds.isEmpty()) {
            CancelDTO cancelDTO = new CancelDTO();
            BeanUtil.copyProperties(saasFormSaveDTO, cancelDTO);
            cancelDTO.setSingle(0);
            cancelDTO.setStatus(1);
            cancelDTO.setBusinessType(XbbRefTypeEnum.INVOICE.getCode());
            cancelDTO.setDataIdList(cancelInvoiceIds);
            listBatchService.cancel(cancelDTO);
        }
        return invoiceIds;
    }

    /**
     * 生成红冲回款单
     *
     * @param redContractEntity 红冲合同实体
     * @param paymentSheetArray 选择关联的回款单
     * @param saasFormSaveDTO   保存入参
     * @throws XbbException 异常
     */
    public List<Long> generateRedPayment(ContractEntityExt redContractEntity, JSONArray paymentSheetArray, SaasFormSaveDTO saasFormSaveDTO) throws XbbException {
        List<Long> redPaymentSheetIds = new ArrayList<>();
        JSONObject newData = saasFormSaveDTO.getNewData();
        if (redContractEntity == null || newData == null) {
            return redPaymentSheetIds;
        }
        if (paymentSheetArray == null || paymentSheetArray.isEmpty()) {
            return redPaymentSheetIds;
        }
        //是否设置红冲回款单的id,老审批应该为true,工作流公司回款单如果开了工作流审批 应该为false,其他情况均为true
        boolean isSetPaymentFlag = true;
        String corpid = saasFormSaveDTO.getCorpid();
        if (commonHelp.isOpenWorkFlow(corpid)) {
            Map<String, Object> params = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            params.put("del", 0);
            params.put("businessType", XbbRefTypeEnum.PAYMENT_SHEET.getCode());
            params.put("corpid", corpid);
            List<PaasFormEntityExt> paasFormEntityExts = paasFormModel.findEntitys(params);
            Long paymentSheetFormId = CollectionsUtil.isNotEmpty(paasFormEntityExts) ? paasFormEntityExts.get(BasicConstant.ZERO).getId() : 0L;
            List<WorkflowEntity> list = workflowFormDataOperationService.getSatisfyTriggerEntitys(corpid,
                    paymentSheetFormId, XbbRefTypeEnum.PAYMENT_SHEET.getCode(), Arrays.asList(TriggerEventTypeEnum.ONLY_ADD.getType(), TriggerEventTypeEnum.ADD_OR_UPDATE.getType()));
            isSetPaymentFlag = !(CollectionsUtil.isNotEmpty(list) && list.stream().map(WorkflowEntity::getEnable).collect(Collectors.toList()).contains(BasicConstant.ONE));
        }
        // 退货退款关联的回款单
        for(Object obj : paymentSheetArray) {
            JSONObject paymentJsonObject = (JSONObject) obj;
            String refundCreatorId = saasFormSaveDTO.getNewPaasFormDataEntity().getCreatorId();
            if (refundCreatorId != null) {
                paymentJsonObject.put(StringConstant.CREATOR_ID, refundCreatorId);
            }
            PaasFormDataEntityExt paymentSheetEntityExt;
            paymentSheetEntityExt = handlePaymentSheetWebPlatformLinkAddData(paymentJsonObject);
            FormDataAddDTO formDataAddDTO = new FormDataAddDTO();
            BeanUtil.copyProperties(paymentSheetEntityExt, formDataAddDTO);
            BeanUtil.copyProperties(saasFormSaveDTO, formDataAddDTO);
            JSONObject dataList = paymentSheetEntityExt.getData();
            dataList.remove(PaymentSheetEnum.INVOICE_AMOUNT.getAttr());
            JSONObject paymentSheetTypeObj = FastJsonHelper.getJsonObjectOrDefaultFromFormData(dataList, PaymentSheetEnum.PAYMENT_SHEET_TYPE.getAttr(), new JSONObject());
            PaymentSheetTypeEnum paymentSheetTypeEnum = PaymentSheetTypeEnum.getByCode(paymentSheetTypeObj.getString("value"));
            JSONArray amountDetail = dataList.getJSONArray(PaasConstant.AMOUNTDETAIL);
            //金额中处理回款单类型从数组格式修正为数字形式
            if (amountDetail != null ) {
                amountDetail.forEach(e -> {
                    JSONObject jsonObject = (JSONObject) e;
                    if(jsonObject.get(PaymentSheetEnum.PAYMENT_SHEET_TYPE.getAttr()) instanceof JSONObject){
                        JSONObject sonTypeObj = jsonObject.getJSONObject(PaymentSheetEnum.PAYMENT_SHEET_TYPE.getAttr());
                        if(sonTypeObj != null && sonTypeObj.getString("value") != null){
                            jsonObject.put(PaymentSheetEnum.PAYMENT_SHEET_TYPE.getAttr(), sonTypeObj.getString("value"));
                        }
                    }
                });
            }
            if (Objects.equals(paymentSheetTypeEnum, PaymentSheetTypeEnum.WRITE_OFF)) {
                dataList.put(PaymentSheetEnum.PAYMENT_SHEET_TYPE.getAttr(), PaymentSheetTypeEnum.RED_WRITE_OFF.getCode());
                formDataAddDTO.setBusinessType(XbbRefTypeEnum.RED_PAYMENT_SHEET.getCode());
                formDataAddDTO.setSubBusinessType(XbbRefTypeEnum.RED_PAYMENT_SHEET.getCode());
            } else if (Objects.equals(paymentSheetTypeEnum, PaymentSheetTypeEnum.WRITE_OFF_PREPAYMENT)) {
                if (Objects.equals(saasFormSaveDTO.getDistributorMark(), DistributorMarkEnum.DISTRIBUTOR.getCode())) {
                    dataList.put(PaymentSheetEnum.PAYMENT_SHEET_TYPE.getAttr(), PaymentSheetTypeEnum.RED_WRITE_OFF_BALANCE.getCode());
                    formDataAddDTO.setBusinessType(XbbRefTypeEnum.RED_WRITE_OFF_BALANCE.getCode());
                    formDataAddDTO.setSubBusinessType(XbbRefTypeEnum.RED_WRITE_OFF_BALANCE.getCode());
                } else {
                    dataList.put(PaymentSheetEnum.PAYMENT_SHEET_TYPE.getAttr(), PaymentSheetTypeEnum.RED_WRITE_OFF_PREPAYMENT.getCode());
                    formDataAddDTO.setBusinessType(XbbRefTypeEnum.RED_WRITE_OFF_PREPAYMENT.getCode());
                    formDataAddDTO.setSubBusinessType(XbbRefTypeEnum.RED_WRITE_OFF_PREPAYMENT.getCode());
                }
            } else {
                throw new XbbException(BusinessTypeErrorCodeEnum.API_ERROR_361001);
            }
            formDataAddDTO.setDataList(dataList);
            formDataAddDTO.setSaasMark(SaasMarkEnum.SAAS.getCode());
            SaasNeedRedundantAttrPojo saasNeedRedundantAttrPojo = new SaasNeedRedundantAttrPojo();
            saasNeedRedundantAttrPojo.setRefundId(saasFormSaveDTO.getNewPaasFormDataEntity().getId());
            formDataAddDTO.setSaasNeedRedundantAttrPoJo(saasNeedRedundantAttrPojo);
            if (Objects.equals(DistributorMarkEnum.DISTRIBUTOR.getCode(), saasFormSaveDTO.getDistributorMark())) {
                formDataAddDTO.setOwnerId(null);
            }else {
                JSONArray ownerJsonArray = paymentJsonObject.getJSONArray(FieldTypeEnum.OWNERID.getAlias());
                JSONArray coUserJsonArray = paymentJsonObject.getJSONArray(FieldTypeEnum.COUSERID.getAlias());
                List<ReturnUserAndDepartmentPojo> ownerId = new ArrayList<>();
                List<ReturnUserAndDepartmentPojo> coUserId = new ArrayList<>();
                if (Objects.nonNull(ownerJsonArray) && ownerJsonArray.size() > BasicConstant.ZERO) {
                    ownerId = JSONArray.parseArray(ownerJsonArray.toJSONString(), ReturnUserAndDepartmentPojo.class);
                }
                if (Objects.nonNull(coUserJsonArray) && coUserJsonArray.size() > BasicConstant.ZERO) {
                    coUserId = JSONArray.parseArray(coUserJsonArray.toJSONString(), ReturnUserAndDepartmentPojo.class);
                }
                formDataAddDTO.setOwnerId(ownerId);
                formDataAddDTO.setCoUserId(coUserId);
            }
            FormDataAddVO formDataAddVO = paasFormDataService.add(formDataAddDTO);
            if (formDataAddVO.getDataId() != null && isSetPaymentFlag) {
                redPaymentSheetIds.add(formDataAddVO.getDataId());
            }
        }
        return redPaymentSheetIds;
    }

    /**
     * 生成红冲应收款
     *
     * @param redContractEntity 红冲合同实体
     * @param paymentArray 选择关联的应收款
     * @param saasFormSaveDTO   保存入参
     * @return java.util.List<java.lang.Long>
     * @throws XbbException
     * @author zcp
     * @since v1.0
     * @version v1.0
     */
    public List<Long> generateRedPaymentPlan(ContractEntityExt redContractEntity, JSONArray paymentArray, SaasFormSaveDTO saasFormSaveDTO) throws XbbException {
        List<Long> redPaymentIds = new ArrayList<>();
        JSONObject newData = saasFormSaveDTO.getNewData();
        if (redContractEntity == null || newData == null) {
            return redPaymentIds;
        }
        if (paymentArray == null || paymentArray.isEmpty()) {
            return redPaymentIds;
        }
        // 退货退款关联的应收款
        for(Object obj : paymentArray) {
            JSONObject paymentJsonObject = (JSONObject) obj;
            String refundCreatorId = saasFormSaveDTO.getNewPaasFormDataEntity().getCreatorId();
            if (refundCreatorId != null) {
                paymentJsonObject.put(StringConstant.CREATOR_ID, refundCreatorId);
            }
            PaasFormDataEntityExt paymentEntityExt = handlePaymentSheetWebPlatformLinkAddData(paymentJsonObject);
            FormDataAddDTO formDataAddDTO = new FormDataAddDTO();
            BeanUtil.copyProperties(paymentEntityExt, formDataAddDTO);
            BeanUtil.copyProperties(saasFormSaveDTO, formDataAddDTO);
            JSONObject dataList = paymentEntityExt.getData();
            formDataAddDTO.setBusinessType(XbbRefTypeEnum.PAYMENT.getCode());
            formDataAddDTO.setSubBusinessType(XbbRefTypeEnum.PAYMENT.getCode());
            formDataAddDTO.setDataList(dataList);
            formDataAddDTO.setSaasMark(SaasMarkEnum.SAAS.getCode());
            SaasNeedRedundantAttrPojo saasNeedRedundantAttrPojo = new SaasNeedRedundantAttrPojo();
            saasNeedRedundantAttrPojo.setRefundId(saasFormSaveDTO.getNewPaasFormDataEntity().getId());
            formDataAddDTO.setSaasNeedRedundantAttrPoJo(saasNeedRedundantAttrPojo);
            if (Objects.equals(DistributorMarkEnum.DISTRIBUTOR.getCode(), saasFormSaveDTO.getDistributorMark())) {
                formDataAddDTO.setOwnerId(null);
            }else {
                JSONArray ownerJsonArray = paymentJsonObject.getJSONArray(FieldTypeEnum.OWNERID.getAlias());
                JSONArray coUserJsonArray = paymentJsonObject.getJSONArray(FieldTypeEnum.COUSERID.getAlias());
                List<ReturnUserAndDepartmentPojo> ownerId = new ArrayList<>();
                List<ReturnUserAndDepartmentPojo> coUserId = new ArrayList<>();
                if (Objects.nonNull(ownerJsonArray) && ownerJsonArray.size() > BasicConstant.ZERO) {
                    ownerId = JSONArray.parseArray(ownerJsonArray.toJSONString(), ReturnUserAndDepartmentPojo.class);
                }
                if (Objects.nonNull(coUserJsonArray) && coUserJsonArray.size() > BasicConstant.ZERO) {
                    coUserId = JSONArray.parseArray(coUserJsonArray.toJSONString(), ReturnUserAndDepartmentPojo.class);
                }
                formDataAddDTO.setOwnerId(ownerId);
                formDataAddDTO.setCoUserId(coUserId);
            }
            //退货退款这时候是新建红冲应收款，所以需要把原应收款的dataId给remove掉
            // formDataAddDTO.setDataId(null); // 字段已被删除
            FormDataAddVO formDataAddVO = paasFormDataService.add(formDataAddDTO);
            if (formDataAddVO.getDataId() != null) {
                redPaymentIds.add(formDataAddVO.getDataId());
            }
        }
        return redPaymentIds;
    }

    /**
     * 生成红冲合同及其关联表
     *
     * @param newPaasFormDataEntity 退货退款实体
     * @param contractEntityExt     合同
     * @param returnAmount          退货金额
     * @param productArray          产品
     * @param flowStatus            审批状态
     * @param isNew 是否新建
     * @return 红冲合同实体
     * @throws XbbException 异常
     */
    public RefundRedContractVO generateRedContract(PaasFormDataEntity newPaasFormDataEntity, ContractEntityExt contractEntityExt, Double returnAmount, JSONArray productArray, Integer flowStatus, Boolean isNew, UserVO userVO) throws XbbException {
        return refundHelp.generateRedContract(newPaasFormDataEntity, contractEntityExt, returnAmount, productArray, flowStatus, isNew, userVO);
    }

    private void saveProduct(JSONArray productArray, String corpid, Long redContractId, JSONObject refundData, Boolean isNew) throws XbbException {
        //折扣，取合同的
        Map<Long, PaasFormDataEntityExt> productMap = formDataValidateProductHelp.product2saveMap(corpid,productArray);
        Integer sort = 0;
        Map<Long, Double> refundNumMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long, Double> refundProductNumMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long, Double> allOldrefundNumMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        List<ContractProductEntity> contractProductEntityList = new ArrayList(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (int i = 0; i < productArray.size(); i++) {
            JSONObject jsonObject = productArray.getJSONObject(i);
            JSONArray seqArray = jsonObject.getJSONArray(ProductConstant.SEQ);
            // 移除序列号相关数据，不存入关联产品数据中
            jsonObject.remove(ProductConstant.SEQ);
            jsonObject.remove(ProductEnum.ENABLE_SERIAL_NUMBER.getSaasAttr());
            jsonObject.remove(ProductEnum.ENABLE_BATCH_SHELF_LIFE.getSaasAttr());

            Long pageProductId = jsonObject.getLong(SelectProductEnum.PRODUCT.getAttr());
            Long refProductId = jsonObject.getLong(BusinessConstant.REF_PRODUCT_ID);
            sort++;
            Double productNum = jsonObject.getDouble(ContractProductEnum.NUM.getAttr());
            Double price = jsonObject.getDouble(RefundProductEnum.PRICE.getAttr());
            price = price != null ? price : 0;
            // 折扣：默认为100%
            Double discount = jsonObject.getDouble(ContractProductEnum.DISCOUNT.getAttr());
            discount = discount == null ? 100 : discount;
            // 备注
            String memo = jsonObject.getString(ContractProductEnum.MEMO.getAttr());
            Double businessUnitPrice = FastJsonHelper.getJsonArrOrDefaultFromFormData(jsonObject, ProductConstant.PRICE, new JSONArray()).toJavaList(MultiUnitPricePoJo.class).stream().collect(Collectors.toMap(MultiUnitPricePoJo::getValue, MultiUnitPricePoJo::getRate)).get(jsonObject.getLong(SelectProductEnum.BUSINESS_UNIT.getAttr()));
            JSONObject productData = productMap.get(pageProductId).getData();
            ContractProductEntity contractProductEntity = new ContractProductEntity();
            contractProductEntity.setCorpid(corpid);
            contractProductEntity.setContractId(redContractId);
            contractProductEntity.setParentId(productData.getLong(ProductEnum.PARENT_ID.getAttr()));
            contractProductEntity.setProductId(pageProductId);
            contractProductEntity.setProductNum(-productNum);
            contractProductEntity.setProductName(productData.getString(ProductEnum.NAME.getAttr()));
            contractProductEntity.setProductNo(productData.getString(ProductEnum.PRODUCT_NO.getAttr()));
            contractProductEntity.setPrice(price);
            contractProductEntity.setDiscount(discount);
            contractProductEntity.setSpecification(productData.getString(ProductEnum.SPECIFICATION_LINK_TEXT.getAttr()));
            contractProductEntity.setContractOutstockNum(0D);
            contractProductEntity.setInstockNum(0D);
            // TODO 这里不应该有为空的情况
            if (Objects.nonNull(refProductId)) {
                contractProductEntity.setRefProductId(refProductId);
                refundNumMap.put(refProductId, productNum);
                Double num = refundProductNumMap.getOrDefault(pageProductId, 0D);
                num += productNum;
                refundProductNumMap.put(pageProductId, num);
            }else {
                Double num = allOldrefundNumMap.getOrDefault(pageProductId, 0D);
                num += productNum;
                allOldrefundNumMap.put(pageProductId, num);
            }
            contractProductEntity.setMemo(memo);
            contractProductEntity.setBarcode(productData.getString(ProductEnum.BARCODE.getAttr()));
            contractProductEntity.setCost(jsonObject.getDouble(SelectProductEnum.COST.getAttr()));
            if (Objects.nonNull(businessUnitPrice)) {
                productData.put(ProductEnum.PRICE.getAttr(),businessUnitPrice);
            }
            contractProductEntity.setHistoricalPrice(productData.getDouble(ProductEnum.PRICE.getAttr()));
            contractProductEntity.setSort(sort);
            contractProductEntity.setType(ContractProductTypeEnum.REFUND.getCode());
            Integer enableMultiUnit = productData.getInteger(ProductEnum.ENABLE_MULTI_UNIT.getAttr());
            if (Objects.equals(enableMultiUnit, 1)) {
                formDataValidateProductHelp.setBusinessUnit(jsonObject, contractProductEntity);
                contractProductEntity.setProductUnit(jsonObject.getString(SelectProductEnum.UNIT.getAttr()));
            } else {
                contractProductEntity.setProductUnit(productData.getString(ProductEnum.UNIT.getAttr()));
                jsonObject.put(SelectProductEnum.UNIT.getAttr(),productData.getString(ProductEnum.UNIT.getAttr()));
            }
            JSONArray imgArr = FastJsonHelper.getJsonArrFromFormData(productData, ProductEnum.PRODUCT_IMGS.getAttr());
            if (Objects.isNull(imgArr) || imgArr.isEmpty()) {
                imgArr = FastJsonHelper.getJsonArrFromFormData(productData, ProductEnum.THUMBNAIL.getAttr());
            } else {
                imgArr = JSONArray.parseArray(JSON.toJSONString(imgArr.subList(0, 1)));
            }
            contractProductEntity.setProductThumbnail(imgArr.toJSONString());
            contractProductEntity.setData(jsonObject);
            contractProductEntityList.add(contractProductEntity);
            contractProductModel.insert(contractProductEntity);
            //
            if (Objects.nonNull(seqArray) && !seqArray.isEmpty()) {
                jsonObject.put(ProductConstant.SEQ, seqArray);
            }
        }
        // TODO lee 只写了一种逻辑
        PaasAppEntity paasAppEntity = paasAppModel.getByAlias(XbbRefTypeEnum.JXC.getAlias(), corpid);
        boolean isOpenJxc = false;
        if (Objects.nonNull(paasAppEntity)) {
            isOpenJxc = paasAppEntity.getEnable() == 1;
        }
        if (isOpenJxc) {
            if (!refundNumMap.isEmpty()) {
                Map<String, Object> params = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                params.put("corpid", corpid);
                params.put("idIn", refundNumMap.keySet());
                params.put("del", DelEnum.NORMAL.getDel());
                List<OutstockProductEntity> outstockProductEntities = outstockProductModel.findEntitys(params);
                Map<Long, Double> refundNumsMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                HashSet<Long> oldOutstockIds = new HashSet<>();
                outstockProductEntities.forEach(item -> {
                    if (Objects.nonNull(item.getRefProductId()) && refundNumMap.containsKey(item.getId())) {
                        item.setInstockNum(Arith.add(item.getInstockNum() == null ? 0D : item.getInstockNum(), refundNumMap.get(item.getId())));
                        refundNumsMap.put(item.getRefProductId(), Arith.add(refundNumsMap.getOrDefault(item.getRefProductId(), 0D), refundNumMap.get(item.getId())));
                    }else {
//                        老数据逻辑
                        oldOutstockIds.add(item.getOutWarehouseId());
                    }
                });
                outstockProductModel.updateBatch(outstockProductEntities, corpid);
                if (!refundNumsMap.isEmpty()) {
                    params.put("idIn", refundNumsMap.keySet());
                    List<ContractProductEntity> contractProductEntities = contractProductModel.findEntitys(params);
                    contractProductEntities.forEach(item -> {
                        if (refundNumsMap.containsKey(item.getId())) {
                            item.setInstockNum(Arith.add(item.getInstockNum(), refundNumsMap.get(item.getId())));
                        }
                    });
                    contractProductModel.updateBatch(contractProductEntities, corpid);
                }
                if (!oldOutstockIds.isEmpty()) {
                    HashSet<Long> contractIds = new HashSet<>();
                    params.put("idIn", oldOutstockIds);
                    List<OutstockEntityExt> entitys = outstockModel.findEntitys(params);
                    entitys.forEach(item -> {
                        Long contractId = item.getData().getLong(OutstockEnum.REF_ID.getAttr());
                        contractIds.add(contractId);
                    });
                    if (!contractIds.isEmpty()) {
                        params.clear();
                        params.put("corpid", corpid);
                        params.put("contractIdIn", contractIds);
                        params.put("del", DelEnum.NORMAL.getDel());
                        List<ContractProductEntity> contractProductEntities = contractProductModel.findEntitys(params);
                        for (ContractProductEntity entity : contractProductEntities) {
                            if (refundProductNumMap.containsKey(entity.getProductId())) {
                                // 剩余未退
                                Double unStockNum = Arith.sub(entity.getProductNum(), entity.getInstockNum());
                                Double amendNum = refundProductNumMap.get(entity.getProductId());
                                Double instockNum;
                                Double inNum = Arith.sub(amendNum, unStockNum);
                                if (inNum > 0) {
                                    instockNum = entity.getProductNum();
                                    refundProductNumMap.put(entity.getProductId(), inNum);
                                }else {
                                    instockNum = Arith.add(entity.getInstockNum(), amendNum);
                                    refundProductNumMap.remove(entity.getProductId());
                                }
                                entity.setInstockNum(instockNum);
                                entity.setUpdateTime(DateTimeUtil.getInt());
                            }
                        }
                        contractProductModel.updateBatch(contractProductEntities, corpid);
                    }
                }
            }
            if (!allOldrefundNumMap.isEmpty()) {
//             退货退款没有refproductid的情况
                Long contractId = refundData.getLong(RefundEnum.CONTRACT_ID.getAttr());
                Map<String, Object> params = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                params.put("corpid", corpid);
                params.put("contractId", contractId);
                params.put("del", DelEnum.NORMAL.getDel());
                List<ContractProductEntity> contractProductEntities = contractProductModel.findEntitys(params);
                contractProductEntities.forEach(item ->{
                    if (allOldrefundNumMap.containsKey(item.getProductId())) {
                        // 剩余未退
                        Double unStockNum = Arith.sub(item.getProductNum(), item.getInstockNum());
                        Double amendNum = allOldrefundNumMap.get(item.getProductId());
                        Double instockNum;
                        Double inNum = Arith.sub(amendNum, unStockNum);
                        if (inNum > 0) {
                            instockNum = item.getProductNum();
                            allOldrefundNumMap.put(item.getProductId(), inNum);
                        }else {
                            instockNum = Arith.add(item.getInstockNum(), amendNum);
                            allOldrefundNumMap.remove(item.getProductId());
                        }
                        item.setInstockNum(instockNum);
                        item.setUpdateTime(DateTimeUtil.getInt());
                    }
                });
                contractProductModel.updateBatch(contractProductEntities, corpid);
            }
        }else {
            if (!refundNumMap.isEmpty()) {
                Map<String, Object> params = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                params.put("corpid", corpid);
                params.put("idIn", refundNumMap.keySet());
                params.put("del", DelEnum.NORMAL.getDel());
                List<ContractProductEntity> contractProductEntities = contractProductModel.findEntitys(params);
                contractProductEntities.forEach(item -> {
                    if (refundNumMap.containsKey(item.getId())) {
                        item.setInstockNum(Arith.add(item.getInstockNum(), refundNumMap.get(item.getId())));
                    }
                });
                contractProductModel.updateBatch(contractProductEntities, corpid);
            }
        }
    }

    private void saveSerial(RefundEntityExt refundEntityExt, JSONArray deepCloneProductArray) throws XbbException {
        JSONObject refundData = refundEntityExt.getData();
        String corpid = refundEntityExt.getCorpid();
        Long refundId = refundEntityExt.getId();
        // 红冲合同
        Long redContractId = refundData.getLong(RefundEnum.RED_CONTRACT_ID.getAttr());
        List<ContractProductEntity> linkProductEntities = contractProductModel.getProductsByConId(redContractId, corpid);
        List<ProductSerialFlowEntity> productSerialFlowEntityList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<String, ProductSerialFlowEntity> productSerialFlowEntityMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Set<String> seqKeyList = new HashSet<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        //
        List<ProductSerialFlowEntity> flowEntityList = productSerialFlowModel.getFlowByRefIdAndBusiness(Collections.singletonList(refundId), XbbRefTypeEnum.REFUND.getCode(), corpid);
        List<String> serialList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        if (CollectionUtils.isNotEmpty(flowEntityList)) {
            flowEntityList.forEach(item -> serialList.add(item.getSeqKey()));
        }
        for (int i = 0; i < deepCloneProductArray.size(); i++) {
            JSONObject productData = deepCloneProductArray.getJSONObject(i);
            JSONArray seqArray = productData.getJSONArray(ProductConstant.SEQ);
            ContractProductEntity linkProductEntity = linkProductEntities.get(i);
            productData.put(BusinessConstant.PRODUCT_SUB_ID, linkProductEntity.getId());
            if (BasicConstant.ZERO.equals(productData.getIntValue(ProductEnum.ENABLE_SERIAL_NUMBER.getSaasAttr())) && (Objects.isNull(seqArray) || seqArray.isEmpty())) {
                continue;
            }
            Long productId = productData.getLong(RefundProductEnum.PRODUCT.getAttr());
            for (int j = 0; j < seqArray.size(); j++) {
                JSONObject seqData = seqArray.getJSONObject(j);
                String serial = seqData.getString(SerialEnum.SERIAL.getAttr());
                String seqKey = productId + "_" + serial;
                if (serialList.contains(seqKey)) {
                    throw new XbbException(ProductErrorCodeEnum.API_ERROR_205094, String.format(ProductErrorCodeEnum.API_ERROR_205094.getMsg(), serial));
                }
                ProductSerialFlowEntity productSerialFlowEntity = new ProductSerialFlowEntity();
                productSerialFlowEntity.setCorpid(corpid);
                productSerialFlowEntity.setProductId(productId);
                productSerialFlowEntity.setSeq(serial);
                productSerialFlowEntity.setMemo(seqData.getString(SerialEnum.MEMO.getAttr()));
                productSerialFlowEntity.setStatus(SerialStatusEnum.OUT_STOCK.getCode());
                productSerialFlowEntity.setDate(DateTimeUtil.getInt());
                productSerialFlowEntity.setBusinessType(XbbRefTypeEnum.REFUND.getCode());
                productSerialFlowEntity.setRefId(refundId);
                productSerialFlowEntity.setRefSheetNo(refundEntityExt.getSerialNo());
                // 关联产品id
                productSerialFlowEntity.setRefProductId(linkProductEntity.getId());
                productSerialFlowEntity.setParentId(linkProductEntity.getParentId());
                productSerialFlowEntity.setBusinessId(refundData.getLong(RefundEnum.CUSTOMER_ID.getAttr()));
                productSerialFlowEntity.setBusinessName(refundData.getString(RefundEnum.CUSTOMER_ID_LINKED_TEXT.getAttr()));
                productSerialFlowEntity.setSeqKey(seqKey);
                productSerialFlowEntity.setDel(BasicConstant.ZERO);

                seqKeyList.add(productSerialFlowEntity.getSeqKey());
                productSerialFlowEntityList.add(productSerialFlowEntity);
                productSerialFlowEntityMap.put(productSerialFlowEntity.getSeqKey(), productSerialFlowEntity);
            }
        }
        if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(productSerialFlowEntityList)) {
            Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            param.put("corpid", corpid);
            param.put("seqKeyIn", seqKeyList);
            param.put(StringConstant.DEL, DelEnum.NORMAL.getDel());
            // 结存记录
            List<ProductSerialBalanceEntity> entitys = productSerialBalanceModel.findEntitys(param);
            for (ProductSerialBalanceEntity entity : entitys) {
                ProductSerialFlowEntity productSerialFlowEntity = productSerialFlowEntityMap.get(entity.getSeqKey());
                entity.setStatus(productSerialFlowEntity.getStatus());
                entity.setBusinessType(productSerialFlowEntity.getBusinessType());
                entity.setRefId(productSerialFlowEntity.getRefId());
                entity.setRefProductId(productSerialFlowEntity.getRefProductId());
                entity.setDate(productSerialFlowEntity.getDate());
                entity.setRefSheetNo(productSerialFlowEntity.getRefSheetNo());
                // 反向操作一波，仓库不变
                productSerialFlowEntity.setWarehouseId(entity.getWarehouseId());
            }
            // 新增流水
            productSerialFlowModel.insertBatch(productSerialFlowEntityList);
            // 更新结存
            productSerialBalanceModel.updateBatch(entitys, corpid);
        }
    }

    /**
     * 更新红冲合同的合同成本，合同毛利，现金毛利
     * @param productArray
     * @param corpid
     * @param redContractEntity
     * @param contractEntityExt
     * @param refundData
     * @param returnAmount
     * @throws XbbException
     */
    public void updateRedContract(JSONArray productArray, String corpid, ContractEntityExt redContractEntity, ContractEntityExt contractEntityExt, JSONObject refundData, Double returnAmount, Boolean isNew, Long refundId) throws XbbException {
        JSONObject redContractData = redContractEntity.getData();
        JSONObject contractData = contractEntityExt.getData();
        Long contractId = contractEntityExt.getId();

        boolean isOpenJxc = ifJXCOpen(corpid);
        // 计算红冲合同的总成本(无产品退货退款时，这个红冲合同的总成本直接默认0)
        Double redContractCost = 0D;
        Map<Long, Double> productIdAndNumMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long, Double> webProductIdAndNumMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<String, Double> batchProductIdAndNumMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        if (!productArray.isEmpty()) {
            for (int i = 0; i < productArray.size(); i++) {
                JSONObject jsonObject = productArray.getJSONObject(i);
                Long pageProductId = jsonObject.getLong(SelectProductEnum.PRODUCT.getAttr());
                Double productNum = jsonObject.getDouble(ContractProductEnum.NUM.getAttr());
                String batchNum = jsonObject.getString(RefundProductEnum.BATCH.getAttr());
                String key = pageProductId.toString();
                if(StringUtils.isNotEmpty(batchNum)){
                    key = key+batchNum;
                }
                if(batchProductIdAndNumMap.containsKey(key)){
                    productNum = Arith.add(batchProductIdAndNumMap.get(key), productNum);
                }
                batchProductIdAndNumMap.put(key,productNum);
                // 退货产品ID以及对应的数量
                if(productIdAndNumMap.containsKey(pageProductId)){
                    productNum = Arith.add(productIdAndNumMap.get(pageProductId), productNum);
                }
                productIdAndNumMap.put(pageProductId, -productNum);
                webProductIdAndNumMap.put(pageProductId, productNum);
            }

            // 开启进销存是直接查询原合同关联的出库单产品成本(同一件产品多次出库，就是每次相加出库成本*每次出库数量/总出库数量)*红冲合同产品表的产品数量(退货产品数量)
            if(isOpenJxc){
                List<Long> outstockIdList = FastJsonHelper.getJsonArrOrDefaultFromFormData(contractData, ContractEnum.OUTSTOCK_ID.getAttr(), new JSONArray()).toJavaList(Long.class);
                if (!outstockIdList.isEmpty()) {
                    Map<String,Object> outstockParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    outstockParam.put("corpid", corpid);
                    outstockParam.put("del", DelEnum.NORMAL.getDel());
                    outstockParam.put("outstockIdIn", outstockIdList);
                    List<OutstockProductEntity> outstockProductList = outstockProductModel.findEntitys(outstockParam);
                    Map<Long, OutstockProductEntity> outstockProductEntityMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    // 算出每个产品对应的成本
                    Map<String, Double> productIdAndCost = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    Map<String, Double> batchProductIdAndCostMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    // 所有的出库记录
                    for (OutstockProductEntity outstockProductEntity : outstockProductList) {
                        Long productId = outstockProductEntity.getProductId();
                        Double productNum = outstockProductEntity.getProductNum() == null ? 0D : outstockProductEntity.getProductNum();
                        Double productCost = outstockProductEntity.getCost() == null ? 0D : outstockProductEntity.getCost();
                        String batchNum = outstockProductEntity.getBatch();
                        String key = productId.toString();
                        if(StringUtils.isNotEmpty(batchNum)){
                            key = key+batchNum;
                        }
                        batchProductIdAndCostMap.put(key, productCost);
                    }
                    // 遍历红冲合同
                    Iterator iterator = batchProductIdAndNumMap.keySet().iterator();
                    while (iterator.hasNext()) {
                        String key = iterator.next().toString();
                        Double productNum = batchProductIdAndNumMap.get(key);
                        if(batchProductIdAndCostMap.containsKey(key)){
                            redContractCost = Arith.add(redContractCost, Arith.mul(productNum, batchProductIdAndCostMap.get(key)));
                        }
                    }
                }
            } else {
                // 不开启进销存是直接查询原合同关联产品表的成本*红冲合同产品表的产品数量(退货产品数量)
                BoolQueryBuilder boolQueryBuilder = boolQuery();
                boolQueryBuilder.filter(termQuery("corpid.keyword",corpid));
                boolQueryBuilder.filter(termQuery(StringConstant.DEL,DelEnum.NORMAL.getDel()));
                boolQueryBuilder.filter(termQuery(ContractProductSubFormEnum.getEsAttr(ContractProductSubFormEnum.TYPE),201));
                boolQueryBuilder.filter(termQuery(ContractProductSubFormEnum.getEsAttr(ContractProductSubFormEnum.CONTRACT_ID), contractId));
                List<String> fieldList = Arrays.asList(ContractProductSubFormEnum.getAttrConnectData(ContractProductSubFormEnum.PRODUCT_ID) , ContractProductSubFormEnum.getAttrConnectData(ContractProductSubFormEnum.CONTRACT_ID), ContractProductSubFormEnum.getAttrConnectData(ContractProductSubFormEnum.PRODUCT_NUM), ContractProductSubFormEnum.getAttrConnectData(ContractProductSubFormEnum.PRICE), ContractProductSubFormEnum.getAttrConnectData(ContractProductSubFormEnum.COST));
                List<PaasFormDataEntity> list =  esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_CONTRACT_PRODUCT,boolQueryBuilder,PaasFormDataEntity.class, fieldList);
                if(list.size() > 0) {
                    List<ContractProductEntity> contractProductEntities = transferSubFormHelper.transferFormDataToContractProductList(list);
                    for (ContractProductEntity contractProductEntity : contractProductEntities) {
                        Long productId = contractProductEntity.getProductId();
                        Double cost = contractProductEntity.getCost() == null ? 0D : contractProductEntity.getCost();
                        if(productIdAndNumMap.containsKey(productId)){
                            Double productCost = Arith.mul(cost, productIdAndNumMap.get(productId));
                            redContractCost = Arith.add(redContractCost, productCost);
                        }
                    }
                }
            }
        }

        // 更新红冲合同的合同成本，合同毛利，现金毛利
        redContractData.put(ContractEnum.CONTRACT_COST.getAttr(), redContractCost);
        redContractData.put(ContractEnum.GROSS_PROFIT.getAttr(), Arith.sub(-returnAmount, redContractCost));
        Double refundAmount = getDoubleOrDefaultFromFormData(refundData, RefundEnum.REFUND_AMOUNT.getAttr() , 0D);
        redContractData.put(ContractEnum.CASH_PROFIT.getAttr(), Arith.sub(-refundAmount, redContractCost));
        // 补充一下更新签订日期
        Long refundSign = FastJsonHelper.getLongOrDefaultFromFormData(refundData, RefundEnum.SIGN_DATE.getAttr(), 0L);
        redContractData.put(ContractEnum.SIGN_TIME.getAttr(), refundSign);
        // 补充更新一下红冲合同金额
        redContractData.put(ContractEnum.AMOUNT.getAttr(), -returnAmount);
        // 签订人更新
        String signUser = FastJsonHelper.getStringFromFormData(refundData, RefundEnum.SIGN_USER.getAttr());
        redContractData.put(ContractEnum.SIGN_PERSON.getAttr(),signUser);

        redContractEntity.setData(redContractData);
        contractModel.update(redContractEntity);

        // 直接重新计算数据比较精确
        resetOldContractData(corpid, contractEntityExt, isOpenJxc, webProductIdAndNumMap, isNew, returnAmount, refundId);
    }

    /**
     * 直接重新计算数据比较精确
     * @param corpid
     * @param contractEntityExt
     * @param isOpenJxc
     * @throws XbbException
     */
    private void resetOldContractData(String corpid, ContractEntityExt contractEntityExt, boolean isOpenJxc, Map<Long, Double> webProductIdAndNumMap, boolean isNew, Double returnAmount, Long refundId) throws XbbException{
        JSONObject contractData = contractEntityExt.getData();
        JSONObject updateContractData = new JSONObject();
        Long contractId = contractEntityExt.getId();
        // 查询出所有关联原合同的退货金额(一对多)
        Map<Long, Double> allContractCostMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);

        // 合同与红冲合同对应map
        Map<Long, List<Long>> contractIdAndRedContractMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);

        // 合同与入库单对应map
        Map<Long, List<Long>> contractIdAndInstockIdMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);

        BoolQueryBuilder oldQueryBuilder = boolQuery();
        oldQueryBuilder.filter(termQuery("corpid.keyword",corpid));
        oldQueryBuilder.filter(termsQuery(RefundEnum.getEsAttr4Keyword(RefundEnum.CONTRACT_ID),Arrays.asList(contractId)));
        oldQueryBuilder.filter(termQuery(StringConstant.DEL,DelEnum.NORMAL.getDel()));
        oldQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, IndexTypeEnum.IDX_SAAS_REFUND.getType()));
        SearchSourceBuilder builder = new SearchSourceBuilder();
        builder.query(oldQueryBuilder);
        PageRequest page = EsUtil.setPage(builder, 1, PaasConstant.ES_MAX_PAGE_SIZE);
        SearchRequest search = new SearchRequest(IndexTypeEnum.IDX_SAAS_REFUND.getIndex());
        search.source(builder);
        XbbAggregatedPage<PaasFormDataEntity> entities = xbbElasticsearchRestTemplate.queryForPages(page, search, PaasFormDataEntity.class);
        Boolean sumSelf = false;
        for (PaasFormDataEntity entity : entities.getContent()) {
            JSONObject data = entity.getData();
            Double returnCost = getDoubleOrDefaultFromFormData(data, RefundEnum.RETURN_AMOUNT.getAttr(), 0D);

            if (Objects.equals(entity.getDataId(), refundId)) {
                // 用于判断当前新建的退货退款是否进入了es，避免下方出现重复累加的问题
                sumSelf = true;
            }
            // 统计所有的退货金额
            if(allContractCostMap.containsKey(contractId)){
                Double cost = allContractCostMap.get(contractId) == null ? 0D : allContractCostMap.get(contractId);
                returnCost = Arith.add(returnCost, cost);
                allContractCostMap.put(contractId, returnCost);
            } else {
                allContractCostMap.put(contractId, returnCost);
            }

            // 合同与红冲合同对应关系
            Long redConId = data.getLong(RefundEnum.RED_CONTRACT_ID.getAttr());
            if(contractIdAndRedContractMap.containsKey(contractId)){
                List<Long> redConIdList = contractIdAndRedContractMap.get(contractId) == null ? new ArrayList<>() : contractIdAndRedContractMap.get(contractId);
                List<Long> idList = new ArrayList<>(redConIdList);
                idList.add(redConId);
                contractIdAndRedContractMap.put(contractId, idList);
            } else {
                contractIdAndRedContractMap.put(contractId, Arrays.asList(redConId));
            }

            // 合同与入库单对应关系
            JSONArray instockIdArr = FastJsonHelper.getJsonArrOrDefaultFromFormData(data, RefundEnum.INSTOCK_ID.getAttr(), new JSONArray());
            if(!instockIdArr.isEmpty()){
                List<Long> instocks = instockIdArr.toJavaList(Long.class);
                if(contractIdAndInstockIdMap.containsKey(contractId)){
                    List<Long> instockList = contractIdAndInstockIdMap.get(contractId) == null ? new ArrayList<>() : contractIdAndInstockIdMap.get(contractId);
                    List<Long> idList = new ArrayList<>(instockList);
                    idList.addAll(instocks);
                    contractIdAndInstockIdMap.put(contractId, idList);
                } else {
                    contractIdAndInstockIdMap.put(contractId, instocks);
                }
            }
        }

        // 查询出所有关联原合同的出库单
        Map<Long, List<Long>> allContractOutMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        // 所有对应的合同实体
        List<ContractEntityExt> contractList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        List<Long> contractIdList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        BoolQueryBuilder entityQueryBuilder = boolQuery();
        entityQueryBuilder.filter(termQuery("corpid.keyword", corpid));
        entityQueryBuilder.filter(termsQuery(FieldTypeEnum.DATAID.getAlias(), Arrays.asList(contractId)));
        entityQueryBuilder.filter(termQuery("del", 0));
        entityQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, IndexTypeEnum.IDX_SAAS_CONTRACT.getType()));
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.query(entityQueryBuilder);
        PageRequest pageRequest = EsUtil.setPage(sourceBuilder, 1, 1);
        SearchRequest searchRequest = new SearchRequest(IndexTypeEnum.IDX_SAAS_CONTRACT.getIndex());
        searchRequest.source(sourceBuilder);
        XbbAggregatedPage<ContractEntityExt> esEntities = xbbElasticsearchRestTemplate.queryForPages(pageRequest, searchRequest, ContractEntityExt.class);
        for (ContractEntityExt entity : esEntities.getContent()) {
            contractList.add(entity);
            contractIdList.add(contractId);

            JSONObject data = entity.getData();
            List<Long> outstockIdList = FastJsonHelper.getJsonArrOrDefaultFromFormData(data, ContractEnum.OUTSTOCK_ID.getAttr(), new JSONArray()).toJavaList(Long.class);

            if(allContractOutMap.containsKey(contractId)){
                List<Long> outIdList = allContractOutMap.get(contractId) == null ? new ArrayList<>() : allContractOutMap.get(contractId);
                List<Long> outIdIn = new ArrayList<>(outIdList);
                outIdIn.addAll(outstockIdList);
                allContractOutMap.put(contractId, outIdIn);
            } else {
                allContractOutMap.put(contractId, outstockIdList);
            }
        }

        Double jxc2UpdateInstockCost = BasicConstant.ZERO_DOUBLE;

        // 查询该合同对应所有入库单的产品
        List<Long> instockList = contractIdAndInstockIdMap.get(contractId) == null ? new ArrayList<>() : contractIdAndInstockIdMap.get(contractId);
        //入库单的产品id及其数量
        Map<Long, Double> instockProductIdAndNum = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        if(!instockList.isEmpty()){
            Map<String,Object> instockProductParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            instockProductParam.put("corpid", corpid);
            instockProductParam.put("instockIdIn",instockList);
            instockProductParam.put("del", 0);
            List<InstockProductEntity> instockProductEntityList = instockProductService.findEntitys(instockProductParam);
            for(InstockProductEntity instockPro : instockProductEntityList){
                // 新数据计算，直接计算所有该合同所有入库单的成本
                Double productNum = instockPro.getProductNum() == null ? 0D : Math.abs(instockPro.getProductNum());
                Double productCost = instockPro.getCost() == null ? 0D : instockPro.getCost();
                jxc2UpdateInstockCost = Arith.add(jxc2UpdateInstockCost, Arith.mul(productNum, productCost));

                // 统计入库单每一件产品的数量
                Long productId = instockPro.getProductId();
                Double num = instockPro.getProductNum();
                if(instockProductIdAndNum.containsKey(productId)){
                    Double inNum = instockProductIdAndNum.get(productId) == null ? BasicConstant.ZERO_DOUBLE : instockProductIdAndNum.get(productId);
                    Double countNum = Arith.add(inNum, num);
                    instockProductIdAndNum.put(productId, countNum);
                } else {
                    instockProductIdAndNum.put(productId, num);
                }
            }
        }

        // 合同与红冲合同退货产品成本对应map
        Map<Long, Double> contractIdAndCostMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);

        // 查询所有的红冲合同
        Iterator entries = contractIdAndRedContractMap.entrySet().iterator();
        while(entries.hasNext()){
            Map.Entry entry = (Map.Entry) entries.next();
            Long key = (Long) entry.getKey();
            List<Long> redConIdList = contractIdAndRedContractMap.get(key);
            Double costAmount = BasicConstant.ZERO_DOUBLE;
            if(redConIdList.size() > 0) {
                Map<Long, Double> productIdAndNumMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                Map<String,Object> redParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                redParam.put("corpid", corpid);
                redParam.put("contractIdIn",redConIdList);
                redParam.put("del", 0);
                // 拿到红冲合同的所有产品
                List<ContractProductEntity> contractProductEntityList = contractProductModel.findEntitys(redParam);

                // 退货产品ID以及对应的数量
                for(ContractProductEntity entity : contractProductEntityList){
                    Long pageProductId = entity.getProductId();
                    Double productNum = entity.getProductNum() == null ? 0D : Math.abs(entity.getProductNum());
                    if(productIdAndNumMap.containsKey(pageProductId)){
                        Double num = productIdAndNumMap.get(pageProductId) == null ? 0D : productIdAndNumMap.get(pageProductId);
                        productNum = Arith.add(productNum, num);
                    }
                    productIdAndNumMap.put(pageProductId, productNum);
                }

                // 新建的时候，红冲合同产品这一步还没有入库，需要直接取前端的数据
                if(isNew && !webProductIdAndNumMap.isEmpty()){
                    if(productIdAndNumMap.isEmpty()){
                        productIdAndNumMap.putAll(webProductIdAndNumMap);
                    } else {
                        Map<Long, Double> webMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                        Iterator productIterator = productIdAndNumMap.keySet().iterator();
                        while (productIterator.hasNext()) {
                            Long id = Long.valueOf(productIterator.next().toString());
                            Double productNum = productIdAndNumMap.get(id);
                            if(webProductIdAndNumMap.containsKey(id)){
                                productNum = Arith.add(productNum, webProductIdAndNumMap.get(id));
                                productIdAndNumMap.put(id, productNum);
                            } else {
                                webMap.putAll(webProductIdAndNumMap);
                            }
                        }
                        if(!webMap.isEmpty()){
                            productIdAndNumMap.putAll(webMap);
                        }
                    }
                } else if(isNew && webProductIdAndNumMap.isEmpty() && !sumSelf){
                    // 当新建时，退款数据还没有入库，这个时候直接塞值(新建只有一条数据)
                    Iterator allEntries = allContractCostMap.entrySet().iterator();
                    while(allEntries.hasNext()){
                        Map.Entry allEntry = (Map.Entry) allEntries.next();
                        Long id = (Long) allEntry.getKey();
                        Double amount = allContractCostMap.get(id);
                        amount = Arith.add(amount, returnAmount);
                        allContractCostMap.put(contractId, amount);
                    }
                }

                //判断是否是新旧数据
                boolean sourceDoc = false;
                for(ContractProductEntity entity : contractProductEntityList){
                    JSONObject data = entity.getData();
                    if (data.containsKey(SelectProductEnum.SOURCE_DOC.getAttr())) {
                        sourceDoc = true;
                        break;
                    }
                }
                // 新数据直接使用累加结果
                if(sourceDoc){
                    contractIdAndCostMap.put(key, jxc2UpdateInstockCost);
                    break;
                }

                //-----------------------旧数据处理---------------------------
                List<Long> outstockIdList = allContractOutMap.get(key);
                if(outstockIdList != null && instockList != null && isOpenJxc){
                    Map<String,Object> outstockParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    outstockParam.put("corpid", corpid);
                    outstockParam.put("del", DelEnum.NORMAL.getDel());
                    outstockParam.put("outstockIdIn", outstockIdList);
                    List<OutstockProductEntity> outstockProductList = outstockProductModel.findEntitys(outstockParam);
                    Map<Long, OutstockProductEntity> outstockProductEntityMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    // 算出每个产品对应的成本
                    Map<Long, Double> productIdAndCost = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    // 所有的出库记录
                    for (OutstockProductEntity outstockProductEntity : outstockProductList) {
                        Long productId = outstockProductEntity.getProductId();
                        Double productNum = outstockProductEntity.getProductNum() == null ? 0D : outstockProductEntity.getProductNum();
                        Double productCost = outstockProductEntity.getCost() == null ? 0D : outstockProductEntity.getCost();
                        // 将所有记录的相同产品的平均成本求出
                        if (outstockProductEntityMap.containsKey(productId)) {
                            OutstockProductEntity oldOutstockProductEntity = outstockProductEntityMap.get(productId);
                            Double oldProductNum = oldOutstockProductEntity.getProductNum() == null ? 0D : oldOutstockProductEntity.getProductNum();
                            Double oldProductCost = oldOutstockProductEntity.getCost() == null ? 0D : oldOutstockProductEntity.getCost();
                            // 上一次的产品总成本
                            Double oldCost = Arith.mul(oldProductNum, oldProductCost);
                            // 这一次的产品总成本
                            Double newCost = Arith.mul(productNum, productCost);
                            // (上一次的产品总成本+这一次的产品总成本)/两次的总数量
                            productCost = Arith.div(Arith.add(oldCost, newCost), Arith.add(oldProductNum, productNum), 2);
                        }
                        outstockProductEntityMap.put(productId, outstockProductEntity);
                        productIdAndCost.put(productId, productCost);
                    }

                    // 遍历入库产品
                    Iterator iterator = instockProductIdAndNum.keySet().iterator();
                    while (iterator.hasNext()) {
                        Long id = Long.valueOf(iterator.next().toString());
                        Double productNum = instockProductIdAndNum.get(id);
                        if(productIdAndCost.containsKey(id)){
                            costAmount = Arith.add(costAmount, Arith.mul(productNum, productIdAndCost.get(id)));
                        }
                    }
                } else if(!isOpenJxc){
                    // 不开启进销存是直接查询原合同关联产品表的成本*红冲合同产品表的产品数量(退货产品数量)
                    BoolQueryBuilder boolQueryBuilder = boolQuery();
                    boolQueryBuilder.filter(termQuery("corpid.keyword",corpid));
                    boolQueryBuilder.filter(termQuery(StringConstant.DEL,DelEnum.NORMAL.getDel()));
                    boolQueryBuilder.filter(termQuery(ContractProductSubFormEnum.getEsAttr(ContractProductSubFormEnum.TYPE), 201));
                    boolQueryBuilder.filter(termQuery(ContractProductSubFormEnum.getEsAttr(ContractProductSubFormEnum.CONTRACT_ID),key));
                    boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, IndexTypeEnum.IDX_SAAS_CONTRACT_PRODUCT.getType()));
                    List<String> fieldList = Arrays.asList(ContractProductSubFormEnum.getAttrConnectData(ContractProductSubFormEnum.PRODUCT_ID), ContractProductSubFormEnum.getAttrConnectData(ContractProductSubFormEnum.CONTRACT_ID), ContractProductSubFormEnum.getAttrConnectData(ContractProductSubFormEnum.PRODUCT_NUM), ContractProductSubFormEnum.getAttrConnectData(ContractProductSubFormEnum.PRICE), ContractProductSubFormEnum.getAttrConnectData(ContractProductSubFormEnum.COST));
                    List<PaasFormDataEntity> list =  esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_CONTRACT_PRODUCT,boolQueryBuilder, PaasFormDataEntity.class, fieldList);
                    if(list.size() > 0) {
                        List<ContractProductEntity> contractProductEntities = transferSubFormHelper.transferFormDataToContractProductList(list);
                        for (ContractProductEntity contractProductEntity : contractProductEntities) {
                            Long productId = contractProductEntity.getProductId();
                            Double cost = contractProductEntity.getCost() == null ? 0D : contractProductEntity.getCost();
                            if(productIdAndNumMap.containsKey(productId)){
                                Double productCost = Arith.mul(cost, productIdAndNumMap.get(productId));
                                costAmount = Arith.add(costAmount, productCost);
                            }
                        }
                    }
                }
            }
            contractIdAndCostMap.put(key, costAmount);
        }

        BoolQueryBuilder boolQueryBuilder = boolQuery();
        boolQueryBuilder.filter(termQuery("corpid.keyword", corpid));
        boolQueryBuilder.filter(termQuery("del", 0));
        boolQueryBuilder.filter(termQuery("data." + OutstockEnum.TYPE.getAttr(), OutstockTypeEnum.CONTRACT_OUTSTOCK.getCode()));
        boolQueryBuilder.filter(termsQuery("data." + OutstockEnum.REF_ID.getAttr(), Arrays.asList(contractId)));
        boolQueryBuilder.filter(termsQuery("flowStatus", Arrays.asList(FlowStatusEnum.NOT_NEED_APPROVAL.getType(), FlowStatusEnum.PASS.getType())));
        boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, IndexTypeEnum.IDX_SAAS_OUTSTOCK.getType()));
        List<PaasFormDataEntityExt> outstockList = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_OUTSTOCK, boolQueryBuilder, PaasFormDataEntityExt.class, Arrays.asList(OutstockEnum.getAttrConnectData(OutstockEnum.REF_ID), FieldTypeEnum.DATAID.getAlias()));

        // 根据出库单获取对应的产品
        List<Long> dataIdIn = new ArrayList<>();
        outstockList.forEach(outstock -> dataIdIn.add(outstock.getDataId()));
        Map<String, Object> outstockParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        outstockParam.put("corpid", corpid);
        outstockParam.put("del", 0);
        outstockParam.put("outstockIdIn", dataIdIn);
        List<OutstockProductEntity> outstockAllProductList = outstockProductModel.findEntitys(outstockParam);

        // 合同和关联的出库单的对应关系
        Map<Long, List<Long>> contractOutstockMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        List<Long> outstockIdList = contractOutstockMap.get(contractId);
        if (outstockIdList == null) {
            outstockIdList = new ArrayList<>();
        }
        for (PaasFormDataEntityExt outstock : outstockList) {
            Long refId = outstock.getData().getLong(OutstockEnum.REF_ID.getAttr());
            if (Objects.equals(contractId, refId)) {
                outstockIdList.add(outstock.getDataId());
            }
        }
        contractOutstockMap.put(contractId, outstockIdList);

        // 合同和出库产品的对应关系
        Map<Long, List<OutstockProductEntity>> contractOutstockProductMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        List<Long> outstockIdLists = contractOutstockMap.get(contractId);
        List<OutstockProductEntity> outstockProductEntityList = contractOutstockProductMap.get(contractId);
        if (outstockProductEntityList == null) {
            outstockProductEntityList = new ArrayList<>();
        }
        for (OutstockProductEntity outstockProductEntity : outstockAllProductList) {
            Long outstockId = outstockProductEntity.getOutWarehouseId();
            if (outstockIdLists.contains(outstockId)) {
                outstockProductEntityList.add(outstockProductEntity);
            }
        }
        contractOutstockProductMap.put(contractId, outstockProductEntityList);

        // 合同和关联产品的对应关系
        List<ContractProductEntity> contractProList = contractProductModel.getContractProductByContractIdIn(corpid, Arrays.asList(contractId));
        Map<Long, List<ContractProductEntity>> contractProductMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        List<ContractProductEntity> contractProductEntityList = contractProductMap.get(contractId);
        if (contractProductEntityList == null) {
            contractProductEntityList = new ArrayList<>();
        }
        for (ContractProductEntity contractProductEntity : contractProList) {
            if (Objects.equals(contractProductEntity.getContractId(), contractId)) {
                contractProductEntityList.add(contractProductEntity);
            }
        }
        contractProductMap.put(contractId, contractProductEntityList);

        // 整理数据
        List<OutstockProductEntity> outstockProductList = contractOutstockProductMap.get(contractId);
        List<ContractProductEntity> contractProductList = contractProductMap.get(contractId);

        // 计算合同出库成本：SUM（已出库产品数量*出库产品成本）
        double realCost = 0D;
        boolean isOld = false;
        // 合并的出库产品数量MAP
        Map<Long, Double> outstockProductNumMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        // 行对应数量
        Map<Long, Double> lineProductNumMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (OutstockProductEntity outstockProductEntity : outstockProductList) {
            if (Objects.isNull(outstockProductEntity.getRefProductId())) {
                isOld = true;
            }
            Long productId = outstockProductEntity.getProductId();
            Double productNum = outstockProductEntity.getProductNum();
            productNum = productNum == null ? 0D : productNum;
            Double cost = outstockProductEntity.getCost();
            cost = cost == null ? 0D : cost;
            realCost = Arith.add(realCost, Arith.mul(productNum, cost));
            if (outstockProductNumMap.containsKey(productId)) {
                outstockProductNumMap.put(productId, Arith.add(outstockProductNumMap.get(productId), productNum));
            } else {
                outstockProductNumMap.put(productId, productNum);
            }
            if (!isOld) {
                Long refProductId = outstockProductEntity.getRefProductId();
                if (lineProductNumMap.containsKey(refProductId)) {
                    lineProductNumMap.put(refProductId, Arith.add(lineProductNumMap.get(refProductId), productNum));
                } else {
                    lineProductNumMap.put(refProductId, productNum);
                }
            }
        }

        // 算出合同中每种产品的平均价
        Map<Long, String> avgCostMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (ContractProductEntity contractProductEntity : contractProductList) {
            Long productId = contractProductEntity.getProductId();
            Double productNum = contractProductEntity.getProductNum() == null ? 0D : Math.abs(contractProductEntity.getProductNum());
            if (isOld) {
                if (avgCostMap.containsKey(productId)) {
                    // map中已经有相同产品，需要计算平均值
                    String productInfo = avgCostMap.get(productId);
                    String[] split = productInfo.split(",");
                    Double preCost = StringUtil.toDouble((split[0]), 0D);
                    Double preNum = StringUtil.toDouble((split[1]), 0D);
                    Double nowCost = SaasProductHelp.calculateCost(preNum, preCost, productNum, contractProductEntity.getCost(), 1);
                    Double nowNum = Arith.add(preNum, productNum);
                    avgCostMap.put(productId, nowCost + "," + nowNum);
                } else {
                    // 将产品id为key，合同产品平均价和数量拼接字符串为value存入map中
                    String productInfo = contractProductEntity.getCost() + "," + productNum;
                    avgCostMap.put(productId, productInfo);
                }
            } else if (lineProductNumMap.containsKey(contractProductEntity.getId())) {
                // 分行已出库数量计算
                contractProductEntity.setContractOutstockNum(lineProductNumMap.get(contractProductEntity.getId()));
            }
        }
        double estimateCost = 0D;
        if (isOld) {
            // 老数据合同预估成本计算
            for (ContractProductEntity contractProductEntity : contractProductList) {
                String productInfo = avgCostMap.get(contractProductEntity.getProductId());
                if (org.apache.commons.lang.StringUtils.isEmpty(productInfo)) {
                    continue;
                }
                String[] productInfos = productInfo.split(",");
                if (outstockProductNumMap.containsKey(contractProductEntity.getProductId())) {
                    if (Arith.sub(contractProductEntity.getProductNum(), outstockProductNumMap.get(contractProductEntity.getProductId())) > 0) {
                        estimateCost = Arith.add(estimateCost, Arith.mul(Arith.sub(contractProductEntity.getProductNum(), outstockProductNumMap.get(contractProductEntity.getProductId())), StringUtil.toDouble((productInfos[0]), 0D)));
                    }
                } else {
                    estimateCost = Arith.add(estimateCost, Arith.mul(contractProductEntity.getProductNum(), StringUtil.toDouble((productInfos[0]), 0D)));
                }
            }
        } else {
            // 新数据合同预估成本计算
            for (ContractProductEntity contractProductEntity : contractProductList) {
                if (Arith.sub(contractProductEntity.getProductNum(), contractProductEntity.getContractOutstockNum()) > 0) {
                    estimateCost = Arith.add(estimateCost, Arith.mul(contractProductEntity.getCost(), Arith.sub(contractProductEntity.getProductNum(), contractProductEntity.getContractOutstockNum())));
                }
            }
        }

        // 合同成本 = 合同产品成本 - 退货产品成本（入库单的产品成本：新数据用入库单的成本，旧数据用出库单的平均成本）+ 其他费用
        Double surchargeAmount = getDoubleOrDefaultFromFormData(contractData, ContractEnum.OTHER_EXPENSE.getAttr(), BasicConstant.ZERO_DOUBLE);
        Double contractCost;
        if(contractIdAndCostMap.containsKey(contractId)){
            Double cost = contractIdAndCostMap.get(contractId) == null ? BasicConstant.ZERO_DOUBLE : contractIdAndCostMap.get(contractId);
            contractCost = Arith.sub(Arith.add(Arith.add(estimateCost, realCost), surchargeAmount), cost);
        } else {
            contractCost = Arith.add(Arith.add(estimateCost, realCost), surchargeAmount);
        }
        updateContractData.put(ContractEnum.CONTRACT_COST.getAttr(), Arith.round(contractCost, 2));

        //合同毛利 = 合同金额 - 退货金额（关联计算）- 合同成本（同上）
        Double amount = getDoubleOrDefaultFromFormData(contractData, ContractEnum.AMOUNT.getAttr(), 0D);
        Double grossProfit;
        if(allContractCostMap.containsKey(contractId)){
            Double cost = allContractCostMap.get(contractId) == null ? BasicConstant.ZERO_DOUBLE : allContractCostMap.get(contractId);
            grossProfit = Arith.sub(Arith.sub(amount, contractCost), cost);
        } else {
            grossProfit = Arith.sub(amount, contractCost);
        }
        updateContractData.put(ContractEnum.GROSS_PROFIT.getAttr(), Arith.round(grossProfit, 2));

        // 合同毛利率
        if (Double.compare(amount, BasicConstant.ZERO_DOUBLE) != 0) {
            updateContractData.put(ContractEnum.GROSS_PROFIT_RATE.getAttr(), Arith.round(Arith.div(grossProfit, amount), 4));
        } else {
            updateContractData.put(ContractEnum.GROSS_PROFIT_RATE.getAttr(), BasicConstant.ZERO_DOUBLE);
        }

        // 现金毛利 = 合同已收款金额 - 合同成本（同上）
        Double finishAmount = getDoubleOrDefaultFromFormData(contractData, ContractEnum.FINISH_AMOUNT.getAttr(), 0D);
        Double cashProfit = Arith.sub(finishAmount, contractCost);
        updateContractData.put(ContractEnum.CASH_PROFIT.getAttr(), cashProfit);
        // 现金毛利率
        if (Double.compare(finishAmount, BasicConstant.ZERO_DOUBLE) != 0) {
            updateContractData.put(ContractEnum.CASH_PROFIT_RATE.getAttr(), Arith.round(Arith.div(cashProfit, finishAmount), 2));
        } else {
            updateContractData.put(ContractEnum.CASH_PROFIT_RATE.getAttr(), BasicConstant.ZERO_DOUBLE);
        }
        UpdateDataEntity updateData = ExplainUtil.getUpdateData(contractEntityExt.getId(), updateContractData, corpid);
        contractModel.updateBatch(Collections.singletonList(updateData), corpid);
    }


    /**
     * 新建格式化解释
     *
     * @param formatExplainDTO 入参
     * @throws XbbException 异常
     */
    @Override
    public void formatAddExplain(FormatExplainDTO formatExplainDTO) throws XbbException {
        List<FieldAttrEntity> explainList = formatExplainDTO.getExplainList();
        String corpid = formatExplainDTO.getCorpid();
        UserVO userVO = formatExplainDTO.getLoginUser();
        Set<String> permSet = userVO.getPermSet();
        FilterAttrOnOffJXCDTO filterAttrOnOffJXCDTO = new FilterAttrOnOffJXCDTO();
        BeanUtil.copyProperties(formatExplainDTO, filterAttrOnOffJXCDTO);
        filterAttrOnOffJXCDTO.setFieldAttrEntityList(explainList);
        filterAttrOnOffJXCDTO.setOperatePageCode(OperatePageEnum.NEW.getCode());
        refundModel.filterAttrOnOffJXC(filterAttrOnOffJXCDTO);
        for (FieldAttrEntity fieldAttrEntity : explainList) {
            Integer fieldType = fieldAttrEntity.getFieldType();
            String attr = fieldAttrEntity.getAttr();
            if (Objects.equals(fieldType, FieldTypeEnum.SELECT_PRODUCT.getType())) {
                explainHelp.formatSelectProductExplains(fieldAttrEntity, XbbRefTypeEnum.REFUND, corpid, OperatePageEnum.NEW.getCode(), false);
            }
            if (Objects.equals(attr, RefundEnum.SIGN_USER.getAttr())) {
                if(fieldAttrEntity.getDefaultAttr() == null || (fieldAttrEntity.getDefaultAttr() != null && fieldAttrEntity.getDefaultAttr().getDefaultList() == null)) {
                    fieldAttrEntity.setDefaultAttr(defaultAttrHelp.setUserDefaultAttrPoJo(formatExplainDTO.getUserId(), formatExplainDTO.getLoginUser().getName(),formatExplainDTO.getLoginUser().getAvatar()));
                }
                // DefaultAttrPoJo defaultAttrPojo = saasUpdateHelp.setUserDefaultAttrPoJo(formatExplainDTO.getUserId(), formatExplainDTO.getLoginUserName(),formatExplainDTO.getLoginUser().getAvatar());
            } else if(Objects.equals(attr, RefundEnum.PAYMENT_SHEETS.getAttr())) {
                //回款单新增权限判断
                if(!permSet.contains(ProPermissionAliasEnum.PAYMENT_SHEET_ADD.getAlias())) {
                    fieldAttrEntity.setEditable(BasicConstant.ZERO);
                }
            } else if(Objects.equals(attr, RefundEnum.PAYMENTS.getAttr())) {
                //红冲应收款权限判断
                if(!permSet.contains(ProPermissionAliasEnum.RED_RECEIVABLES.getAlias())) {
                    fieldAttrEntity.setEditable(BasicConstant.ZERO);
                }
            } else if(Objects.equals(attr, RefundEnum.INVOICES.getAttr())) {
                //红冲/作废发票按钮权限判断
                if(!permSet.contains(ProPermissionAliasEnum.INVOICE_CANCEL.getAlias()) && !permSet.contains(ProPermissionAliasEnum.INVOICE_RED.getAlias())) {
                    fieldAttrEntity.setEditable(BasicConstant.ZERO);
                }
            }
        }
    }

    /**
     * 格式化移动端列表页
     *
     * @param formDataListDTO 用户
     * @param esEntities      业务实体集合
     * @param totalCount      总数
     * @return ListAppVO
     * @throws XbbException
     * @author long.rao
     * @date 2019-03-11 13:50
     */
    @Override
    public ListAppVO formatRefundAppList(FormDataListDTO formDataListDTO, List<PaasFormDataEntityExt> esEntities, Integer totalCount) throws XbbException {
        List<AppListPojo> appListPojos = new ArrayList<>();
        String corpid = formDataListDTO.getCorpid();
        List<Long> dataIdList = new ArrayList<>();
        esEntities.forEach(item -> {
            JSONObject itemData = item.getData();
            try {
                saasSaveHelp.formatLinkBusiness4Save(itemData, RefundEnum.CUSTOMER_ID.getAttr(), RefundEnum.CUSTOMER_ID_LINKED_TEXT.getAttr(), RefundEnum.CONTRACT_ID_LINKED_TEXT.getFieldType());
            } catch (XbbException e) {
                e.printStackTrace();
            }
            try {
                dataIdList.add(FastJsonHelper.getLongOrDefaultFromFormData(itemData, RefundEnum.CUSTOMER_ID.getAttr(),0L));
            } catch (XbbException e) {
                e.printStackTrace();
            }
        });

        PaasFormExplainEntity paasFormExplainEntity = paasFormExplainModel.getByFormId(formDataListDTO.getFormId(), corpid);
        if (paasFormExplainEntity == null) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.FORM_EXPLAIN_NOT_EXIST);
        }
        //  获取字段解释信息，并且过滤不可见字段 start
        List<FieldAttrEntity> explainList = JSONArray.parseArray(paasFormExplainEntity.getExplains(), FieldAttrEntity.class);

        // ---- 获取用户和部门容器start
        UserAndDepartmentGetDTO userAndDepartmentGetDTO = new UserAndDepartmentGetDTO();
        BeanUtil.copyProperties(formDataListDTO, userAndDepartmentGetDTO);
        userAndDepartmentGetDTO.setExplainList(explainList);
        UserAndDepartmentGetVO userAndDepartmentGetVO = userHelp.getUserDepartmentMap(userAndDepartmentGetDTO);
        Map<String, UserEntity> userMap = userAndDepartmentGetVO.getUserMap();

        // 关联客户
        Map<Long, String> cusIdAndName = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        if (dataIdList != null) {
            Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            param.put("corpid", corpid);
            param.put("del", DelEnum.NORMAL.getDel());
            param.put("ids", dataIdList);
            List<CustomerEntityExt> cusExt = customerModel.findEntitys(param);
            cusExt.forEach(item -> cusIdAndName.put(item.getId(), item.getData().getString(CustomerManagementEnum.NAME.getAttr())));
        }

        for (PaasFormDataEntityExt refund : esEntities) {
            JSONObject data = refund.getData();
            Long refundId = refund.getDataId();
            String ownerId = refund.getOwnerId();

            // 签订人
            String signUser = FastJsonHelper.getStringOrDefaultFromFormData(data, RefundEnum.SIGN_USER.getAttr(), "");
            String refundSignUser = RefundEnum.SIGN_USER.getAttrName() + "：" + signUser;
            Long customerId = FastJsonHelper.getLongOrDefaultFromFormData(data, RefundEnum.CUSTOMER_ID.getAttr(),0L);
            String customerName = cusIdAndName.getOrDefault(customerId, "");

            JSONArray explains = new JSONArray();
            JSONObject superScript = new JSONObject();
            JSONArray tags = new JSONArray();
            JSONObject others = new JSONObject();

            //commonHelp.setRefundInfo(refund, data, customerName, refundSignUser, explains, others);
            Long time = data.getLongValue(RefundEnum.SIGN_DATE.getAttr());
            String signTimeStr = time == 0L ? "" : DateTimeUtil.getStringEpochSecond(time, DateTimeUtil.SDFDate);
            // 解释
            // 退货退款合同名称
            //String refundName = (String) data.getOrDefault(RefundEnum.REFUND_NAME.getAttr(), "");
            //explains.add("合同名称:" + name);
            //explains.add(refundSignUser);

            // 签订日期
            //String refundSignDate = RefundEnum.SIGN_DATE.getAttrName() + ":";
            //explains.add(refundSignDate + signTimeStr);
            // 客户
            /*String refundLinkedText = RefundEnum.CUSTOMER_ID.getAttrName() + ":";
            explains.add(refundLinkedText + customerName);*/
            //其他
            others.put("serialNo", refund.getSerialNo());
            // 退货金额
            String amount = StringUtil.formatDouble(data.getDoubleValue(RefundEnum.RETURN_AMOUNT.getAttr()));
            others.put("amount", amount + UnitEnum.MONEY.getName());

            // 负责人
            /*String userName = saasUpdateHelp.getStringOrDefaultFromFormData(data, FieldTypeEnum.OWNERID.getAlias(), "");

            // 回显负责人
            UserEntity userEntity = userMap.get(ownerId);
            String value = Objects.isNull(userEntity) ? "" : userEntity.getName();
            String name = userName == "" ? value : userName;

            String mainUserStr = "负责人：";
            explains.add(mainUserStr + name);
            summaryList.add(commonHelp.setSummary(RefundEnum.OWNER_ID.getAttrName(), userName));*/

            List<SummaryDataPoJo> summaryList = FastJsonHelper.getJsonArrOrDefaultFromFormData(data, BasicConstant.SUMMARY_LIST, new JSONArray()).toJavaList(SummaryDataPoJo.class);
            List<SummaryDataPoJo> lablesList = FastJsonHelper.getJsonArrOrDefaultFromFormData(data, BasicConstant.LABELS_LIST, new JSONArray()).toJavaList(SummaryDataPoJo.class);
            List<FormTitlePoJo> titleList = FastJsonHelper.getJsonArrOrDefaultFromFormData(data, BasicConstant.TITLE_LIST, new JSONArray()).toJavaList(FormTitlePoJo.class);
            if (titleList.isEmpty()) {
                FormTitlePoJo titlePoJo = new FormTitlePoJo();
                titlePoJo.setValue(Collections.singletonList(refund.getSerialNo()));
                titleList.add(titlePoJo);
            }

            //app系统关联数据展示需要 others 和 superScript
            data.put("others",others);
            data.put("superScript",superScript);
            appListPojos.add(new AppListPojo(refundId, titleList, summaryList, superScript, new ArrayList<>(), others));
            JSONObject sourceData = refund.getSourceData();
            if (data.containsKey(RefundEnum.CUSTOMER_ID.getAttr()) && sourceData.containsKey(RefundEnum.CUSTOMER_ID.getAttr())) {
                data.put(RefundEnum.CUSTOMER_ID.getAttr(), sourceData.get(RefundEnum.CUSTOMER_ID.getAttr()));
            }
        }
        ListAppVO listAppVO = new ListAppVO();
        listAppVO.setList(appListPojos);
        listAppVO.setTotalCount(totalCount);
        return listAppVO;
    }

    /**
     * 格式化产品，显示给前端
     *
     * @param dataList            实体数据
     * @param saasAnalysisDataDTO 数据解析DTO
     * @throws XbbException
     * @author long.rao
     * @date 2019-03-02 16:35
     */
    @Override
    public void formatProduct4Show(JSONObject dataList, SaasAnalysisDataDTO saasAnalysisDataDTO) throws XbbException {
        if (dataList == null || saasAnalysisDataDTO == null) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028);
        }
        String corpid = saasAnalysisDataDTO.getCorpid();
        JSONArray productArray = new JSONArray();
        JSONObject productFinalObj = new JSONObject();

        // 兼容退货退款产品回显
        List<ContractProductEntity> contractProductList = new ArrayList<>();
        if (saasAnalysisDataDTO.getForProcess()) {
            JSONArray productArr = FastJsonHelper.getJsonArrOrDefaultFromFormData(FastJsonHelper.getJsonObjectOrDefaultFromFormData(dataList, RefundEnum.PRODUCTS.getAttr(), new JSONObject()), StringConstant.PRODUCT_LIST, new JSONArray());
            Map<Long, ProductEntityExt> productMap = productModel.getProductMap(corpid, productArr);
            refundModel.getProductList(corpid, contractProductList, productArr, productMap);
        } else {
            // 通过退货退款关联红冲合同查询ID(其实一个退货退款单只是关联一个合同)
            Long redContractId = dataList.getLong(RefundEnum.RED_CONTRACT_ID.getAttr());
            // 通过红冲合同ID查询产品ID
            Map<String, Object> params = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            params.put("corpid", corpid);
            params.put("contractId", redContractId);
            params.put("del", DelEnum.NORMAL.getDel());
            contractProductList = contractProductModel.findEntitys(params);
            if (contractProductList == null || contractProductList.size() == 0) {
                productFinalObj.put(StringConstant.PRODUCT_LIST, productArray);
                JSONObject others = new JSONObject();
                productFinalObj.put(BusinessConstant.OTHERS, others);
                dataList.put(RefundEnum.PRODUCTS.getAttr(), productFinalObj);
                return;
            }
        }
        List<Long> productIds = new ArrayList<>();
        Set<Long> productIdSet = new HashSet<>();
        for (ContractProductEntity entity : contractProductList) {
            if (entity == null) {
                break;
            }
            productIds.add(entity.getProductId());
            productIdSet.add(entity.getProductId());
        }
        // 通过产品ID查询产品
        Map<String, Object> productParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        productParam.put("corpid", corpid);
        productParam.put("del", DelEnum.NORMAL.getDel());
        productParam.put("idIn", productIds);
        List<ProductEntityExt> productEntityExts = productModel.findEntitys(productParam);
        if (productEntityExts == null || productEntityExts.size() == 0) {
            return;
        }
        Map<Long, ProductEntityExt> map = new HashMap<>(productEntityExts.size());
        for (ProductEntityExt entityExt : productEntityExts) {
            map.put(entityExt.getId(), entityExt);
        }
        // 获取关联产品需要展示的字段
        BusinessProductEnum businessProductEnum = BusinessProductEnum.getByCode(XbbRefTypeEnum.REFUND.getCode());
        // 用于存放当前启用的产品模板解释的map
        Map<String, FieldAttrEntity> nowProductExplainMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<String, FieldAttrEntity> nowBomProductExplainMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        explainHelp.getRelativeProductExplainsFromDB(corpid, nowProductExplainMap, nowBomProductExplainMap);

        // 获取产品
        List<PaasFormDataEntityExt> productList = productService.getProductListById(productIdSet, corpid, null);
        Set<Long> parentIdInSet = new HashSet<>();
        Map<Long, PaasFormDataEntityExt> productMapExt = new HashMap<>(productList.size());
        productList.forEach((item) -> {
            productMapExt.put(item.getDataId(), item);
            JSONObject data = item.getData();
            if (Objects.nonNull(data) && Objects.nonNull(data.getLong(ProductEnum.PARENT_ID.getAttr()))) {
                parentIdInSet.add(data.getLong(ProductEnum.PARENT_ID.getAttr()));
            }
        });
        // 获取父类产品
        List<PaasFormDataEntityExt> parentProductList = productService.getProductListById(parentIdInSet, corpid, null);
        Map<Long, PaasFormDataEntityExt> parentProductMap = new HashMap<>(productList.size());
        parentProductList.forEach((item) -> parentProductMap.put(item.getDataId(), item));

        Map<Integer, JSONObject> productMap = new TreeMap<>();
        if (businessProductEnum != BusinessProductEnum.UNKNOW) {
            List<RelativeProductEnum> businessProductEnumList = businessProductEnum.getList();
            for (ContractProductEntity entity : contractProductList) {
                JSONArray attrArray = new JSONArray();
                JSONObject productObj = new JSONObject();
                Long productId = entity.getProductId();
                if (map.containsKey(productId)) {
                    JSONObject productData = map.get(productId).getData();

                    Long parentId = productData.getLong(ProductEnum.PARENT_ID.getAttr());
                    PaasFormDataEntityExt parentDataEntity = productModel.getByKey(parentId, corpid);
                    boolean priceHide = false;
                    if (parentDataEntity != null) {
                        //协同团队
                        Map<Long, List<String>> mainUserMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                        Map<Long, List<String>> coUserMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                        userTeamService.getUserIdMap(Collections.singletonList(parentId), corpid, XbbRefTypeEnum.PRODUCT.getCode(), false, mainUserMap, coUserMap);
                        HandlerExplainDTO handlerExplainDTO = new HandlerExplainDTO();
                        BeanUtil.copyProperties(saasAnalysisDataDTO, handlerExplainDTO);
                        handlerExplainDTO.setCreatorId(parentDataEntity.getCreatorId());
                        handlerExplainDTO.setOwnerId(mainUserMap.getOrDefault(parentDataEntity.getDataId(), new ArrayList<>()));
                        handlerExplainDTO.setCoUserId(coUserMap.getOrDefault(parentDataEntity.getDataId(), new ArrayList<>()));
                        handlerExplainDTO.setExplainList(new ArrayList<>(nowProductExplainMap.values()));
                        priceHide = ExplainUtil.isFieldNeedHide(nowProductExplainMap.getOrDefault(ProductEnum.PRICE.getSaasAttr(), new FieldAttrEntity()), handlerExplainDTO);
                    }

                    JSONObject productObject = parentProductMap.get(productData.getLong(ProductEnum.PARENT_ID.getAttr())).getData();
                    String productNo = productObject == null ? "" : productObject.getString(ProductEnum.PRODUCT_NO.getAttr());
                    Double price = entity.getPrice();
                    price = price == null ? Double.valueOf(0D) : price;
                    Double productNum = entity.getProductNum();
                    productNum = productNum == null ? Double.valueOf(0D) : Math.abs(productNum);
                    String memo = entity.getMemo();
                    Double discount = entity.getDiscount();
                    for (RelativeProductEnum productEnum : businessProductEnumList) {
                        String saasAttr = productEnum.getSaasAttr();
                        FieldAttrEntity fieldAttrEntity = null;
                        if (nowProductExplainMap.containsKey(saasAttr)) {
                            fieldAttrEntity = nowProductExplainMap.get(saasAttr);
                        }
                        switch (productEnum) {
                            case NAME:
                                JsonHelperUtil.addToJSONArray(attrArray, saasUpdateHelp.formatSelectProduct4Show(RelativeProductEnum.NAME, entity.getProductName(), fieldAttrEntity));
                                break;
                            case SPECIFICATION:
                                // 格式化规格
                                String specification = specificationModel.joinSpecification(entity.getSpecification());
                                JsonHelperUtil.addToJSONArray(attrArray, saasUpdateHelp.formatSelectProduct4Show(RelativeProductEnum.SPECIFICATION, specification, fieldAttrEntity));
                                break;
                            case PRODUCT_PRICE:
                                Double productPrice = entity.getPrice();
                                productPrice = productPrice == null ? Double.valueOf(0D) : productPrice;
                                JSONObject priceObj = saasUpdateHelp.formatSelectProduct4Show(RelativeProductEnum.PRODUCT_PRICE, productPrice, fieldAttrEntity);
                                if (priceObj != null) {
                                    priceObj.put("hidePrice", priceHide);
                                    JsonHelperUtil.addToJSONArray(attrArray, priceObj);
                                }
                                //JsonHelperUtil.addToJSONArray(attrArray, saasUpdateHelp.formatSelectProduct4Show(RelativeProductEnum.PRODUCT_PRICE, productPrice, fieldAttrEntity));
                                break;
                            case SALE_DISCOUNT:
                                JsonHelperUtil.addToJSONArray(attrArray, saasUpdateHelp.formatSelectProduct4Show(RelativeProductEnum.SALE_DISCOUNT, discount, fieldAttrEntity));
                                break;
                            case SALE_PRODUCT_PRICE:
                                JsonHelperUtil.addToJSONArray(attrArray, saasUpdateHelp.formatSelectProduct4Show(RelativeProductEnum.SALE_PRODUCT_PRICE, price, fieldAttrEntity));
                                break;
                            case NUM:
                                JsonHelperUtil.addToJSONArray(attrArray, saasUpdateHelp.formatSelectProduct4Show(RelativeProductEnum.NUM, productNum, fieldAttrEntity));
                                break;
                            case MEMO:
                                JsonHelperUtil.addToJSONArray(attrArray, saasUpdateHelp.formatSelectProduct4Show(RelativeProductEnum.MEMO, memo, fieldAttrEntity));
                                break;
                            case UNIT:
                                // TODO 单位回显 存的key是0,1,2 回显对应的单位
                                String productUnit = entity.getProductUnit();
                                String unitStr = productModel.getProductUnitTextByValue(productUnit, fieldAttrEntity);
                                JsonHelperUtil.addToJSONArray(attrArray, saasUpdateHelp.formatSelectProduct4Show(RelativeProductEnum.UNIT, unitStr, fieldAttrEntity));
                                break;
                            case SUBTOTAL:
                                Double subTotal = price * productNum;
                                JsonHelperUtil.addToJSONArray(attrArray, saasUpdateHelp.formatSelectProduct4Show(RelativeProductEnum.SUBTOTAL, subTotal, fieldAttrEntity));
                                break;
                            case PRODUCT_NO:
                                JsonHelperUtil.addToJSONArray(attrArray, saasUpdateHelp.formatSelectProduct4Show(RelativeProductEnum.PRODUCT_NO, productNo, fieldAttrEntity));
                                break;
                            default:
                                break;
                        }
                        productObj.put("result", attrArray);
                        productObj.put(StringConstant.SAAS_LINK_BUSINESS_ID, entity.getProductId());
                        productObj.put(StringConstant.BUSINESS_PRODUCT_ID, entity.getId());
                    }
                }
                productMap.put(entity.getSort(), productObj);
            }
            // 产品排序
            for (JSONObject jsonObject : productMap.values()) {
                productArray.add(jsonObject);
            }
            productFinalObj.put(StringConstant.PRODUCT_LIST, productArray);
            JSONObject others = new JSONObject();
            productFinalObj.put(BusinessConstant.OTHERS, others);
            dataList.put(RefundEnum.PRODUCTS.getAttr(), productFinalObj);
        }
    }


    /**
     * 获取退货退款关联产品
     *
     * @param businessProductListDTO
     * @param dataList
     * @return
     * @throws
     * @author 有利
     * @date: 2019-04-09 16:42
     * @version v1.0
     * @since v1.0
     */
   /* @Override
    public BusinessProductListVO getRefundProductList(BusinessProductListDTO businessProductListDTO, JSONObject dataList, boolean refund) throws XbbException {
        BusinessProductListVO businessProductListVO = new BusinessProductListVO();
        // 返回给前端的接受对象
        JSONObject productFinalObj = new JSONObject();
        String corpid = businessProductListDTO.getCorpid();
        UserEntity userEntity = userModel.getByKey(businessProductListDTO.getUserId(), corpid);
        Long refundId = businessProductListDTO.getDataId();
        Integer sourceBusinessType = businessProductListDTO.getSourceBusinessType();
        List<ConditionsEntityExt> conditions = new ArrayList<>();
        conditions.add(EsUtil.packageContions(FieldTypeEnum.DATAID.getAlias(), Collections.singletonList(refundId), ConditionEnum.EQUAL, FieldTypeEnum.DATAID.getType()));
        Integer businessType;
        PaasFormDataEntityExt refundData;

        boolean isInstock = Objects.equals(sourceBusinessType, XbbRefTypeEnum.INSTOCK.getCode());

        Long contractId;
        Long oldContractId;
        JSONArray instockIdArr = new JSONArray();
        if (refund) {
            businessType = XbbRefTypeEnum.REFUND.getCode();
            PaasFormDataEsListVO paasFormDataEsListVO = saasDetailTabService.getEsListOnlyByCondition(corpid, businessType, conditions);
            List<PaasFormDataEntityExt> paasFormDataESList = paasFormDataEsListVO.getPaasFormDataESList();
            if (paasFormDataESList.size() == 0) {
                return businessProductListVO;
            }
            refundData = paasFormDataESList.get(0);
            if (refundData == null) {
                return businessProductListVO;
            }
            JSONObject reData = refundData.getData();
            if(reData == null){
                return businessProductListVO;
            }
            contractId = reData.getLong(RefundEnum.RED_CONTRACT_ID.getAttr());
            oldContractId = reData.getLong(RefundEnum.CONTRACT_ID.getAttr());
            instockIdArr = FastJsonHelper.getJsonArrOrDefaultFromFormData(reData, RefundEnum.INSTOCK_ID.getAttr(), new JSONArray());
        } else {
            contractId = refundId;
            oldContractId = refundId;
        }
        // 退货退款合同币种
        ContractEntityExt contract = contractModel.getByKey(oldContractId, corpid);
        if (Objects.isNull(contract)) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001.getCode(), MessageConstant.FORM_DATA_NOT_EXIST);
        }
        JSONObject contractData = contract.getData();
        if (Objects.isNull(contractData)) {
            throw new XbbException(ContractErrorCodeEnum.API_ERROR_203001);
        }
        // jxc开启时:查询退货出库产品  jxc关闭时:查询退货合同产品
        boolean isOpenJxc = ifJXCOpen(corpid);
        List<OutstockProductEntity> outstockProductList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Set<Long> productIds = new HashSet<>();
        Map<Long, Double> product = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        PageHelper pageHelper = new PageHelper();
        // 查询出库产品
        if (isOpenJxc) {
            // 红冲合同出库产品信息
            JSONArray outstoArray = contractData.getJSONArray(ContractEnum.OUTSTOCK_ID.getAttr());
            List<Long> outstockIds = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            if (outstoArray != null) {
                outstockIds = outstoArray.toJavaList(Long.class);
            }
            Map<String, Object> outModelMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            outModelMap.put(ParameterConstant.CORPID, corpid);
            outModelMap.put("outstockIdIn", outstockIds);
            outModelMap.put(ParameterConstant.DEL, DelEnum.NORMAL.getDel());
            outModelMap.put(ParameterConstant.PAGE, businessProductListDTO.getPage());
//            pageHelper = PageHelperUtil.getPageHelper(outModelMap, outstockProductModel, businessProductListDTO.getPageSize());
//            outstockProductList = (List<OutstockProductEntity>) PageHelperUtil.getEntityList(outModelMap, pageHelper, outstockProductModel);
            outstockProductList = outstockProductModel.findEntitys(outModelMap);
        }
        Map<Long, Double> valueMap =  new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        // 查询合同产品
        List<ContractProductEntity> contractProductList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        if(refund || !isOpenJxc){
            Map<String, Object> modelMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            modelMap.put(ParameterConstant.CORPID, corpid);
            modelMap.put("contractId", contractId);
            modelMap.put(ParameterConstant.DEL, DelEnum.NORMAL.getDel());
            modelMap.put(ParameterConstant.PAGE, businessProductListDTO.getPage());
            pageHelper = PageHelperUtil.getPageHelper(modelMap, contractProductModel, businessProductListDTO.getPageSize());
            contractProductList = (List<ContractProductEntity>) PageHelperUtil.getEntityList(modelMap, pageHelper, contractProductModel);

            contractProductList.forEach(item -> {
                Double productNum = Math.abs(item.getProductNum());
                Long productId = item.getProductId();
                if (product.containsKey(productId)) {
                    productNum = Arith.add(productNum, product.get(productId));
                }
                product.put(productId, productNum);

                productIds.add(productId);
                valueMap.put(productId, productNum);
            });

        } else {
            outstockProductList.forEach(item -> {
                Double productNum = Math.abs(item.getProductNum());
                if (product.containsKey(item.getProductId())) {
                    productNum = Arith.add(productNum, product.get(item.getProductId()));
                }
                product.put(item.getProductId(), productNum);
            });

            // 根据原合同查询出红冲合同对应的产品，即退货产品
            Map<Long, Double> productIdAndSum = paasFormDataService.getRedProduct(corpid, oldContractId);
            for(Map.Entry<Long, Double> pro : product.entrySet()){
                Long key = pro.getKey();
                Double outstockProValue = pro.getValue() == null ? 0D : pro.getValue();
                Double productValue = productIdAndSum.get(key) == null? 0D : productIdAndSum.get(key);
                Double newNum = outstockProValue - productValue;
                if (newNum > 0D) {
                    productIds.add(key);
                    valueMap.put(key, newNum);
                }
            }
        }

        if(productIds.isEmpty()){
            productIds.add(-1L);
        }

        if(isInstock){
            // 获取已经入库的产品
            Map<Long, Double> insProductMap =  new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            if(!instockIdArr.isEmpty()){
                List<Long> instocks = instockIdArr.toJavaList(Long.class);
                Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                param.put(ParameterConstant.CORPID, corpid);
                param.put(ParameterConstant.DEL, DelEnum.NORMAL.getDel());
                param.put("instockIdIn", instocks);
                List<InstockProductEntity> insProducts = instockProductService.findEntitys(param);
                insProducts.forEach(item -> {
                    Double productNum = item.getProductNum();
                    if (insProductMap.containsKey(item.getProductId())) {
                        productNum = Arith.add(productNum, insProductMap.get(item.getProductId()));
                    }
                    insProductMap.put(item.getProductId(), productNum);
                });
                // 获取红冲合同剩余未入库产品
                List<ContractProductEntity> getRedSurplusProduct = contractService.getRedSurplusProduct(corpid, contractId, null, null);
                if(!getRedSurplusProduct.isEmpty()){
                    getRedSurplusProduct.forEach(item -> valueMap.put(item.getProductId(), item.getProductNum()));
                }
            }
        }

        // 获取产品
        List<PaasFormDataEntityExt> productList = productService.getProductListById(productIds, corpid, null);
        Set<Long> parentIdInSet = new HashSet<>();
        Map<Long, PaasFormDataEntityExt> productMap = new HashMap<>(productList.size());
        productList.forEach((item) -> {
            productMap.put(item.getDataId(), item);
            JSONObject data = item.getData();
            if (Objects.nonNull(data) && Objects.nonNull(data.getLong(ProductEnum.PARENT_ID.getAttr()))) {
                parentIdInSet.add(data.getLong(ProductEnum.PARENT_ID.getAttr()));
            }
        });
        // 获取父类产品
        List<PaasFormDataEntityExt> parentProductList = productService.getProductListById(parentIdInSet, corpid, null);
        Map<Long, PaasFormDataEntityExt> parentProductMap = new HashMap<>(productList.size());
        parentProductList.forEach((item) -> parentProductMap.put(item.getDataId(), item));

        Map<String, FieldAttrEntity> explainMap = paasFormExplainService.getFieldAttrMapByBusinessType(businessProductListDTO.getBusinessType(), corpid);

        // 用于存放当前启用的产品模板解释的map
        Map<String, FieldAttrEntity> nowProductExplainMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        saasAddHelp.getRelativeProductExplainsFromDB(corpid, nowProductExplainMap, null);

        JSONArray productArray = new JSONArray();
        JSONObject othersObj = new JSONObject();
        Map<Integer, JSONObject> productSortMap = new TreeMap<>();
        // 得到该公司设置的金额小数精度
//        Integer amountPrecision = companyConfigService.getAmountPrecision(corpid);
        double totalProductMoney = 0D;
        // 获取“数字”的小数精度
//        Integer numberPrecision = companyConfigService.getNumberPrecision(corpid);
        FieldAttrEntity amountFieldAttrEntity = new FieldAttrEntity();
        FieldAttrEntity numFieldAttrEntity = new FieldAttrEntity();
        if(nowProductExplainMap.containsKey(ProductEnum.PRICE.getSaasAttr())) {
            amountFieldAttrEntity = nowProductExplainMap.get(ProductEnum.PRICE.getSaasAttr());
        }
        if(nowProductExplainMap.containsKey(ProductEnum.STOCK.getSaasAttr())) {
            numFieldAttrEntity = nowProductExplainMap.get(ProductEnum.STOCK.getSaasAttr());
        }
        Integer amountPrecision = amountFieldAttrEntity.getAccuracy();
        Integer numberPrecision = numFieldAttrEntity.getAccuracy();

        Integer sort = 0;
        boolean totalProductMoneyHide = false;
        if (isOpenJxc) {
            List<Long> productIdList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            for (OutstockProductEntity item : outstockProductList) {
                sort++;
                Long productId = item.getProductId();
                // 避免同一件产品多次出库之后被退货退款多次记录
                if(productIdList.contains(productId)){
                    continue;
                }
                productIdList.add(productId);
                if(productMap.get(productId) == null){
                    continue;
                }
                JSONObject productData = productMap.get(productId).getData();
                if (productData == null) {
                    continue;
                }
                JSONObject productObject = parentProductMap.get(productData.getLong(ProductEnum.PARENT_ID.getAttr())).getData();
                String productNo = productObject == null ? "" : productObject.getString(ProductEnum.PRODUCT_NO.getAttr());
                // 出库单的产品单价，就是合同的产品最后售价
                Double productPrice = item.getProductPrice() == null ? 0.00D : item.getProductPrice();
                if(valueMap.get(productId) == null){
                    continue;
                }
                Double num = new Double(Math.abs(valueMap.get(productId)));
                Double productNum = attrDecimalPrecisionHelper.setPrecision(num, numberPrecision);
                productPrice = attrDecimalPrecisionHelper.setPrecision(productPrice, amountPrecision);
                FormatRelativeProductEntityExt formatProduct = new FormatRelativeProductEntityExt();
                formatProduct.setProductId(productId);
                formatProduct.setRefId(item.getId());
                formatProduct.setProductName(item.getProductName());
                formatProduct.setProductNum(productNum);
                String thumbnail = "";
                JSONArray jsonArray = productData.getJSONArray(ProductEnum.PRODUCT_IMGS.getAttr());
                if (Objects.nonNull(jsonArray) && !jsonArray.isEmpty()){
                    thumbnail = jsonArray.getString(jsonArray.size()-1);
                }
                formatProduct.setImageUrl(thumbnail);
                String specification = item.getProductSpecification();
                formatProduct.setProductSpecification(specificationModel.joinSpecification(specification));
                String unitObject = productObject == null ? "" : productObject.getString(ProductEnum.UNIT.getAttr());
                formatProduct.setProductUnit(unitObject);
                formatProduct.setMemo(item.getMemo());
                formatProduct.setProductPrice(productPrice);
                formatProduct.setProductNo(productNo);
                Double subTotal = productPrice * productNum;
                // 小计
                totalProductMoney = Arith.add(totalProductMoney, subTotal);
                formatProduct.setSaleSubtotal(attrDecimalPrecisionHelper.setPrecision(subTotal, amountPrecision));

                formatProduct.setSaleDiscount(item.getDiscount());
                formatProduct.setSaleProductPrice(productPrice);
                JSONObject productObj;
                if(isInstock){
                    InstockProductEntityExt instockProductEntityExt = new InstockProductEntityExt();
                    BeanUtil.copyProperties(item, instockProductEntityExt);
                    instockProductEntityExt.setCost(item.getCost());
                    instockProductEntityExt.setProductNum(productNum);

                    FormatInstockProductDTO formatInstockProductDTO = new FormatInstockProductDTO();
                    BeanUtil.copyProperties(businessProductListDTO, formatInstockProductDTO);
                    formatInstockProductDTO.setNowProductExplainMap(nowProductExplainMap);

                    ProductStockInfoEntity productStockInfo = new ProductStockInfoEntity();
                    productStockInfo.setMemo(item.getMemo());
                    instockProductEntityExt.setProductStockInfoEntity(productStockInfo);
                    formatInstockProductDTO.setInstockProductExt(instockProductEntityExt);
                    formatInstockProductDTO.setUserEntity(userEntity);
                    productObj = instockService.getFormatProductJsonArray(formatInstockProductDTO);
                } else {
                    productObj = getJsonObject(businessProductListDTO, corpid, userEntity, nowProductExplainMap, formatProduct);
                }
                productSortMap.put(sort, productObj);

                JSONArray array = productObj.getJSONArray(StringConstant.RESULT);
                boolean priceHide = false;
                for (Object obj : array) {
                    JSONObject productInfo = (JSONObject) obj;
                    if (Objects.equals(productInfo.get("attr"), "productPrice")) {
                        priceHide = productInfo.getBoolean("hidePrice");
                    }
                }

                if (priceHide) {
                    totalProductMoneyHide = true;
                }
            }
        } else {
            for (ContractProductEntity item : contractProductList) {
                sort++;
                Long productId = item.getProductId();
                if(productMap.get(productId) == null){
                    continue;
                }
                JSONObject productData = productMap.get(productId).getData();
                if (productData == null) {
                    continue;
                }
                JSONObject productObject = parentProductMap.get(productData.getLong(ProductEnum.PARENT_ID.getAttr())).getData();
                String productNo = productObject == null ? "" : productObject.getString(ProductEnum.PRODUCT_NO.getAttr());
                Double productPrice;
                if (item.getPrice().equals(-1d)) {
                    productPrice = 0d;
                } else {
                    productPrice = item.getPrice();
                }
                Double num = new Double(Math.abs(item.getProductNum()));
                Double productNum = attrDecimalPrecisionHelper.setPrecision(num, numberPrecision);
                productPrice = attrDecimalPrecisionHelper.setPrecision(productPrice, amountPrecision);
                FormatRelativeProductEntityExt formatProduct = new FormatRelativeProductEntityExt();
                formatProduct.setParentId(item.getParentId());
                formatProduct.setProductId(productId);
                formatProduct.setRefId(item.getId());
                formatProduct.setProductName(item.getProductName());
                formatProduct.setProductNum(productNum);
                String thumbnail = "";
                JSONArray jsonArray = productData.getJSONArray(ProductEnum.PRODUCT_IMGS.getAttr());
                if (Objects.nonNull(jsonArray) && !jsonArray.isEmpty()){
                    thumbnail = jsonArray.getString(jsonArray.size()-1);
                }
                formatProduct.setImageUrl(thumbnail);
                String specification = item.getSpecification();
                formatProduct.setProductSpecification(specificationModel.joinSpecification(specification));
                String unitObject = productObject == null ? "" : productObject.getString(ProductEnum.UNIT.getAttr());
                formatProduct.setProductUnit(unitObject);
                formatProduct.setMemo(item.getMemo());
                Double price = attrDecimalPrecisionHelper.setPrecision(item.getPrice(), amountPrecision);
                formatProduct.setProductPrice(price);
                formatProduct.setProductNo(productNo);
                Double subTotal = productPrice * productNum;
                // 小计
                totalProductMoney = Arith.add(totalProductMoney, subTotal);
                formatProduct.setSaleSubtotal(attrDecimalPrecisionHelper.setPrecision(subTotal, amountPrecision));

                formatProduct.setSaleDiscount(item.getDiscount());
                formatProduct.setSaleProductPrice(productPrice);
                JSONObject productObj;
                if(isInstock){
                    InstockProductEntityExt instockProductEntityExt = new InstockProductEntityExt();
                    BeanUtil.copyProperties(item, instockProductEntityExt);
                    instockProductEntityExt.setCost(item.getCost());
                    instockProductEntityExt.setProductNum(productNum);

                    FormatInstockProductDTO formatInstockProductDTO = new FormatInstockProductDTO();
                    BeanUtil.copyProperties(businessProductListDTO, formatInstockProductDTO);
                    formatInstockProductDTO.setNowProductExplainMap(nowProductExplainMap);

                    ProductStockInfoEntity productStockInfo = new ProductStockInfoEntity();
                    productStockInfo.setMemo(item.getMemo());
                    instockProductEntityExt.setProductStockInfoEntity(productStockInfo);
                    formatInstockProductDTO.setInstockProductExt(instockProductEntityExt);
                    formatInstockProductDTO.setUserEntity(userEntity);
                    productObj = instockService.getFormatProductJsonArray(formatInstockProductDTO);
                } else {
                    productObj = getJsonObject(businessProductListDTO, corpid, userEntity, nowProductExplainMap, formatProduct);
                }
                productSortMap.put(sort, productObj);

                JSONArray array = productObj.getJSONArray(StringConstant.RESULT);
                boolean priceHide = false;
                for (Object obj : array) {
                    JSONObject productInfo = (JSONObject) obj;
                    if (Objects.equals(productInfo.get("attr"), "productPrice")) {
                        priceHide = productInfo.getBoolean("hidePrice");
                    }
                }

                if (priceHide) {
                    totalProductMoneyHide = true;
                }
            }
        }

        othersObj.put("unit", contractData.getDouble(ContractEnum.UNIT.getAttr()) == null ? I18nMessageUtil.getMessage(CommonConstant.YUAN) : contractData.getDouble(ContractEnum.UNIT.getAttr()));
        String totalMoney = totalProductMoneyHide ? StringConstant.INVISIBLE_VALUE : attrDecimalPrecisionHelper.formatMoneyPrecision(totalProductMoney, explainMap, RefundEnum.REFUND_AMOUNT.getAttr());
        othersObj.put(BusinessConstant.TOTAL_PRODUCT_MONEY, totalMoney);

        // 产品排序
        productArray.addAll(productSortMap.values());
        productFinalObj.put(StringConstant.PRODUCT_LIST, productArray);
        productFinalObj.put(BusinessConstant.OTHERS, othersObj);
        String attrStr = RefundEnum.PRODUCTS.getAttr();
        productFinalObj.put(StringConstant.REDUNDANT_FIELD_ATTR_BEGIN_FLAG, attrStr);

        if (businessProductListDTO.getDetailGet()) {
            productFinalObj.put(BusinessConstant.EXPLAINS, saasGetHelp.getSelectProductExplains(XbbRefTypeEnum.REFUND, businessProductListDTO.getBusinessType(), corpid, ContractEnum.PRODUCT.getAttr()));
        } else {
            ProductExplainDTO productExplainDTO = new ProductExplainDTO();
            BeanUtil.copyProperties(businessProductListDTO, productExplainDTO);
            productExplainDTO.setAttr(ContractEnum.PRODUCT.getAttr());
            productExplainDTO.setXbbRefTypeEnum(XbbRefTypeEnum.getByCode(businessProductListDTO.getSourceBusinessType()));
            productExplainDTO.setTargetCode(XbbRefTypeEnum.CONTRACT.getCode());
            productFinalObj.put(BusinessConstant.EXPLAINS, saasUpdateHelp.getSelectProductExplains(productExplainDTO));
        }
        businessProductListVO.setProduct(productFinalObj);
        businessProductListVO.setPageHelper(pageHelper);
        return businessProductListVO;
    }*/

//    private JSONObject getJsonObject(BusinessProductListDTO businessProductListDTO, String corpid, UserEntity userEntity,
//                                     Map<String, FieldAttrEntity> nowProductExplainMap, FormatRelativeProductEntityExt formatProduct) throws XbbException {
//        FormatRelativeProductDTO formatRelativeProductDTO = new FormatRelativeProductDTO();
//        BeanUtil.copyProperties(businessProductListDTO, formatRelativeProductDTO);
//        formatRelativeProductDTO.setBusinessType(XbbRefTypeEnum.REFUND.getCode());
//        formatRelativeProductDTO.setTargetBusinessType(businessProductListDTO.getBusinessType());
//        formatRelativeProductDTO.setCorpid(corpid);
//        formatRelativeProductDTO.setNowProductExplainMap(nowProductExplainMap);
//        formatRelativeProductDTO.setFormatRelativeProductEntityExt(formatProduct);
//        formatRelativeProductDTO.setUserEntity(userEntity);
//        JSONObject productObj = productService.getFormatProductJsonArray(formatRelativeProductDTO);
//        return productObj;
//    }

    /**
     * 批量删除退货退款
     *
     * @param refundDeleteBatchDTO
     * @return RefundDeleteBatchVO
     * @throws XbbException 业务异常
     * @author youli.chen
     * @date 2019/3/13 14:02
     */
    @Override
    public RefundDeleteBatchVO deleteBatch(RefundDeleteBatchDTO refundDeleteBatchDTO) throws XbbException {
        RefundDeleteBatchVO refundDeleteBatchVO = new RefundDeleteBatchVO();
        // TODO 删除权限校验
        List<Long> idIn = refundDeleteBatchDTO.getDataIdList();
        if (idIn != null && idIn.size() > BasicConstant.MAX_DEL_BATCH_COUNT) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100079, String.format(SystemErrorCodeEnum.API_ERROR_100079.getMsg(), BasicConstant.MAX_DEL_BATCH_COUNT));
        }
        String corpid = refundDeleteBatchDTO.getCorpid();
        List<Long> redContractIdIn = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        List<Long> oldContractIdIn = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        List<Long> deleteIdIn = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);

        Map<String, Object> param = BeanUtil.convertBean2Map(refundDeleteBatchDTO, true);
        param.put("idIn", idIn);
        param.put("corpid", corpid);
        param.put("del", 0);
        List<RefundEntityExt> refundExtList = refundModel.findEntitys(param);
        if (Objects.isNull(refundExtList)) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
        }

        // 序列号关联表单删除校验
        if (CollectionUtils.isNotEmpty(idIn)) {
            productSerialService.preCheckDelSerial(idIn, corpid, XbbRefTypeEnum.REFUND.getCode());
        }

        List<Long> conId = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        List<Long> physicalDelIds = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        physicalDelIds.addAll(idIn);
        Map<String, String> noAndName= new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);

        // 合同与红冲合同对应map
        Map<Long, List<Long>> contractIdAndRedContractMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        // 合同与退货金额对应map
        Map<Long, Double> contractIdAndReturnCostMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);

        //key为红冲合同Id,value为退款单id,一对一关系
        Map<Long, Long> redContractIdAndRefundId = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<Long, Long> refundIdAndContractId = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (RefundEntityExt item : refundExtList) {
            deleteIdIn.add(item.getId());
            JSONObject itemData = item.getData();
            Long redConId =  itemData.getLong(RefundEnum.RED_CONTRACT_ID.getAttr());
            if (Objects.nonNull(redConId)) {
                redContractIdIn.add(redConId);
                redContractIdAndRefundId.put(redConId,item.getId());
            }
            Long oldConId = FastJsonHelper.getLongOrDefaultFromFormData(itemData, RefundEnum.CONTRACT_ID.getAttr(), 0L);
            refundIdAndContractId.put(item.getId(), oldConId);
            oldContractIdIn.add(oldConId);

            if (physicalDelIds.contains(item.getId())) {
                physicalDelIds.remove(item.getId());
            }

            if (Objects.nonNull(redConId)) {
                if(contractIdAndRedContractMap.containsKey(oldConId)){
                    List<Long> redConIdList = contractIdAndRedContractMap.get(oldConId) == null ? new ArrayList<>() : contractIdAndRedContractMap.get(oldConId);
                    List<Long> idList = new ArrayList<>(redConIdList);
                    idList.add(redConId);
                    contractIdAndRedContractMap.put(oldConId, idList);
                } else {
                    contractIdAndRedContractMap.put(oldConId, Arrays.asList(redConId));
                }
            }
            Double returnCost = getDoubleOrDefaultFromFormData(itemData, RefundEnum.RETURN_AMOUNT.getAttr(), 0D);
            if(contractIdAndReturnCostMap.containsKey(oldConId)){
                Double cost = contractIdAndReturnCostMap.get(oldConId) == null ? 0D : contractIdAndReturnCostMap.get(oldConId);
                returnCost = Arith.add(returnCost, cost);
                contractIdAndReturnCostMap.put(oldConId, returnCost);
            } else {
                contractIdAndReturnCostMap.put(oldConId, returnCost);
            }

            String no = item.getSerialNo();
            String name = FastJsonHelper.getStringOrDefaultFromFormData(itemData, RefundEnum.REFUND_NAME.getAttr(), "");
            noAndName.put(no, name);
        }

        // 查询出所有关联原合同的退货退款，并筛除出当前需要删除的红冲合同
        Map<Long, List<Long>> allContractMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        // 查询出所有关联原合同的退货金额，并筛除出当前需要删除的红冲合同
        Map<Long, Double> allContractCostMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);

        BoolQueryBuilder oldQueryBuilder = boolQuery();
        oldQueryBuilder.filter(termQuery("corpid.keyword",corpid));
        oldQueryBuilder.filter(termsQuery(RefundEnum.getEsAttr4Keyword(RefundEnum.CONTRACT_ID),oldContractIdIn));
        oldQueryBuilder.filter(termQuery(StringConstant.DEL,DelEnum.NORMAL.getDel()));
        oldQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, IndexTypeEnum.IDX_SAAS_REFUND.getType()));
        SearchSourceBuilder builder = new SearchSourceBuilder();
        builder.query(oldQueryBuilder);
        PageRequest page = EsUtil.setPage(builder, 1, PaasConstant.ES_MAX_PAGE_SIZE);
        SearchRequest search = new SearchRequest(IndexTypeEnum.IDX_SAAS_REFUND.getIndex());
        search.source(builder);
        XbbAggregatedPage<PaasFormDataEntity> entities = xbbElasticsearchRestTemplate.queryForPages(page, search, PaasFormDataEntity.class);
        for (PaasFormDataEntity entity : entities.getContent()) {
            JSONObject data = entity.getData();
            Long contractId = FastJsonHelper.getLongOrDefaultFromFormData(data, RefundEnum.CONTRACT_ID.getAttr(), 0L);
            Long redContractId = FastJsonHelper.getLongOrDefaultFromFormData(data, RefundEnum.RED_CONTRACT_ID.getAttr(), 0L);
            Double returnCost = getDoubleOrDefaultFromFormData(data, RefundEnum.RETURN_AMOUNT.getAttr(), 0D);

            if(allContractMap.containsKey(contractId)){
                List<Long> redConIdList = allContractMap.get(contractId) == null ? new ArrayList<>() : allContractMap.get(contractId);
                List<Long> idList = new ArrayList<>(redConIdList);
                idList.add(redContractId);
                allContractMap.put(contractId, idList);
            } else {
                allContractMap.put(contractId, Arrays.asList(redContractId));
            }

            if(allContractCostMap.containsKey(contractId)){
                Double cost = allContractCostMap.get(contractId) == null ? 0D : allContractCostMap.get(contractId);
                returnCost = Arith.add(returnCost, cost);
                allContractCostMap.put(contractId, returnCost);
            } else {
                allContractCostMap.put(contractId, returnCost);
            }
        }

        // 所有的红冲合同（排除删除的）
        Iterator allEntries = allContractMap.entrySet().iterator();
        while(allEntries.hasNext()) {
            Map.Entry entry = (Map.Entry) allEntries.next();
            Long key = (Long) entry.getKey();
            List<Long> allRedConIdList = allContractMap.get(key);
            // 不存在不包含的情况，不做处理
            if(contractIdAndRedContractMap.containsKey(key)){
                List<Long> redConIdList = contractIdAndRedContractMap.get(key) == null ? new ArrayList<>() : contractIdAndRedContractMap.get(key);
                List<Long> idList = new ArrayList<>(allRedConIdList);
                // 取差集
                idList.removeAll(redConIdList);
                contractIdAndRedContractMap.put(key, idList);
            }
        }

        // 所有的退货金额（排除删除的）
        Iterator allCostEntries = allContractCostMap.entrySet().iterator();
        while(allCostEntries.hasNext()) {
            Map.Entry entry = (Map.Entry) allCostEntries.next();
            Long key = (Long) entry.getKey();
            Double allCost = allContractCostMap.get(key);
            // 不存在不包含的情况，不做处理
            if(contractIdAndReturnCostMap.containsKey(key)){
                Double cost = contractIdAndReturnCostMap.get(key) == null ? 0D : contractIdAndReturnCostMap.get(key);
                allCost = Arith.sub(allCost, cost);
                allContractCostMap.put(key, allCost);
            }
        }

        // 所有对应的合同实体
        List<ContractEntityExt> contractList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        List<Long> contractIdList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        BoolQueryBuilder entityQueryBuilder = boolQuery();
        entityQueryBuilder.filter(termQuery("corpid.keyword", corpid));
        entityQueryBuilder.filter(termsQuery(FieldTypeEnum.DATAID.getAlias(), oldContractIdIn));
        entityQueryBuilder.filter(termQuery("del", 0));
        entityQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, IndexTypeEnum.IDX_SAAS_CONTRACT.getType()));
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.query(entityQueryBuilder);
        PageRequest pageRequest = EsUtil.setPage(sourceBuilder, 1, PaasConstant.ES_MAX_PAGE_SIZE);
        SearchRequest searchRequest = new SearchRequest(IndexTypeEnum.IDX_SAAS_CONTRACT.getIndex());
        searchRequest.source(sourceBuilder);
        XbbAggregatedPage<ContractEntityExt> esEntities = xbbElasticsearchRestTemplate.queryForPages(pageRequest, searchRequest, ContractEntityExt.class);
        for (ContractEntityExt entity : esEntities.getContent()) {
            Long contractId = entity.getDataId();
            contractList.add(entity);
            contractIdList.add(contractId);
        }

        // 合同与红冲合同退货产品成本对应map
        Map<Long, Double> contractIdAndCostMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);

        // 这里查询的都是之前的数据（排除删除的）
        boolean ifJXCOpen = ifJXCOpen(corpid);
        Iterator entries = contractIdAndRedContractMap.entrySet().iterator();
        while(entries.hasNext()){
            Map.Entry entry = (Map.Entry) entries.next();
            Long key = (Long) entry.getKey();
            List<Long> redConIdList = contractIdAndRedContractMap.get(key);
            Double costAmount = BasicConstant.ZERO_DOUBLE;
            if(redConIdList.size() > 0) {
                Map<Long, Double> productIdAndNumMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                Map<String,Object> redParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                redParam.put("corpid", corpid);
                redParam.put("contractIdIn",redConIdList);
                redParam.put("del", 0);
                // 拿到红冲合同的所有产品
                List<ContractProductEntity> contractProductEntityList = contractProductModel.findEntitys(redParam);
                // 退货产品ID以及对应的数量
                for(ContractProductEntity entity : contractProductEntityList){
                    Long pageProductId = entity.getProductId();
                    Double productNum = entity.getProductNum() == null ? 0D : Math.abs(entity.getProductNum());
                    if(productIdAndNumMap.containsKey(pageProductId)){
                        Double num = productIdAndNumMap.get(pageProductId) == null ? 0D : productIdAndNumMap.get(pageProductId);
                        productNum = Arith.add(productNum, num);
                    }
                    productIdAndNumMap.put(pageProductId, productNum);
                }
                if(ifJXCOpen){
                    // 如果退货退款能删除，说明在入库单那里已经处理好合同的成本计算问题，这里就不做考虑
                    costAmount = BasicConstant.ZERO_DOUBLE;
                } else if(!ifJXCOpen){
                    // 不开启进销存是直接查询原合同关联产品表的成本*红冲合同产品表的产品数量(退货产品数量)
                    BoolQueryBuilder boolQueryBuilder = boolQuery();
                    boolQueryBuilder.filter(termQuery("corpid.keyword",corpid));
                    boolQueryBuilder.filter(termQuery(StringConstant.DEL,DelEnum.NORMAL.getDel()));
                    boolQueryBuilder.filter(termQuery(ContractProductSubFormEnum.getEsAttr(ContractProductSubFormEnum.TYPE),201));
                    boolQueryBuilder.filter(termQuery(ContractProductSubFormEnum.getEsAttr(ContractProductSubFormEnum.CONTRACT_ID), key));
                    boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, IndexTypeEnum.IDX_SAAS_CONTRACT_PRODUCT.getType()));
                    List<String> fieldList = Arrays.asList(ContractProductSubFormEnum.getAttrConnectData(ContractProductSubFormEnum.PRODUCT_ID), ContractProductSubFormEnum.getAttrConnectData(ContractProductSubFormEnum.CONTRACT_ID), ContractProductSubFormEnum.getAttrConnectData(ContractProductSubFormEnum.PRODUCT_NUM), ContractProductSubFormEnum.getAttrConnectData(ContractProductSubFormEnum.PRICE), ContractProductSubFormEnum.getAttrConnectData(ContractProductSubFormEnum.COST));
                    List<PaasFormDataEntity> list =  esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_CONTRACT_PRODUCT,boolQueryBuilder, PaasFormDataEntity.class, fieldList);
                    if(list.size() > 0) {
                        List<ContractProductEntity> contractProductEntities = transferSubFormHelper.transferFormDataToContractProductList(list);
                        for (ContractProductEntity contractProductEntity : contractProductEntities) {
                            Long productId = contractProductEntity.getProductId();
                            Double cost = contractProductEntity.getCost() == null ? 0D : contractProductEntity.getCost();
                            if(productIdAndNumMap.containsKey(productId)){
                                Double productCost = Arith.mul(cost, productIdAndNumMap.get(productId));
                                costAmount = Arith.add(costAmount, productCost);
                            }
                        }
                    }
                }
            }
            contractIdAndCostMap.put(key, costAmount);
        }

        BoolQueryBuilder boolQueryBuilder = boolQuery();
        boolQueryBuilder.filter(termQuery("corpid.keyword", corpid));
        boolQueryBuilder.filter(termQuery("del", 0));
        boolQueryBuilder.filter(termQuery("data." + OutstockEnum.TYPE.getAttr(), OutstockTypeEnum.CONTRACT_OUTSTOCK.getCode()));
        boolQueryBuilder.filter(termsQuery("data." + OutstockEnum.REF_ID.getAttr(), oldContractIdIn));
        boolQueryBuilder.filter(termsQuery("flowStatus", Arrays.asList(FlowStatusEnum.NOT_NEED_APPROVAL.getType(), FlowStatusEnum.PASS.getType())));
        boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, IndexTypeEnum.IDX_SAAS_OUTSTOCK.getType()));
        List<PaasFormDataEntityExt> outstockList = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_OUTSTOCK, boolQueryBuilder, PaasFormDataEntityExt.class, Arrays.asList(OutstockEnum.getAttrConnectData(OutstockEnum.REF_ID), FieldTypeEnum.DATAID.getAlias()));

        // 根据出库单获取对应的产品
        List<Long> dataIdIn = new ArrayList<>();
        outstockList.forEach(outstock -> dataIdIn.add(outstock.getDataId()));
        Map<String, Object> outstockParam = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        outstockParam.put("corpid", corpid);
        outstockParam.put("del", 0);
        outstockParam.put("outstockIdIn", dataIdIn);
        List<OutstockProductEntity> outstockAllProductList = outstockProductModel.findEntitys(outstockParam);

        // 合同和关联的出库单的对应关系
        Map<Long, List<Long>> contractOutstockMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (ContractEntityExt contractEntity : contractList) {
            Long contractId = contractEntity.getId();
            List<Long> outstockIdList = contractOutstockMap.get(contractId);
            if (outstockIdList == null) {
                outstockIdList = new ArrayList<>();
            }
            for (PaasFormDataEntityExt outstock : outstockList) {
                Long refId = outstock.getData().getLong(OutstockEnum.REF_ID.getAttr());
                if (Objects.equals(contractId, refId)) {
                    outstockIdList.add(outstock.getDataId());
                }
            }
            contractOutstockMap.put(contractId, outstockIdList);
        }

        // 合同和出库产品的对应关系
        Map<Long, List<OutstockProductEntity>> contractOutstockProductMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (ContractEntityExt contractEntity : contractList) {
            Long contractId = contractEntity.getId();
            List<Long> outstockIdList = contractOutstockMap.get(contractId);
            List<OutstockProductEntity> outstockProductEntityList = contractOutstockProductMap.get(contractId);
            if (outstockProductEntityList == null) {
                outstockProductEntityList = new ArrayList<>();
            }
            for (OutstockProductEntity outstockProductEntity : outstockAllProductList) {
                Long outstockId = outstockProductEntity.getOutWarehouseId();
                if (outstockIdList.contains(outstockId)) {
                    outstockProductEntityList.add(outstockProductEntity);
                }
            }
            contractOutstockProductMap.put(contractId, outstockProductEntityList);
        }

        // 合同和关联产品的对应关系
        List<ContractProductEntity> contractProList = contractProductModel.getContractProductByContractIdIn(corpid, contractIdList);
        Map<Long, List<ContractProductEntity>> contractProductMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        for (ContractEntityExt contractEntity : contractList) {
            Long contractId = contractEntity.getId();
            List<ContractProductEntity> contractProductList = contractProductMap.get(contractId);
            if (contractProductList == null) {
                contractProductList = new ArrayList<>();
            }
            for (ContractProductEntity contractProductEntity : contractProList) {
                if (Objects.equals(contractProductEntity.getContractId(), contractId)) {
                    contractProductList.add(contractProductEntity);
                }
            }
            contractProductMap.put(contractId, contractProductList);
        }

        // TODO 如果该退货退款合同有已生成退货入库单时，不允许删除(批量时只要有一个有问题就返回错误)

        List<Long> refundIdList = new ArrayList<>();
        List<String> refundSerialNos = new ArrayList<>();
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder queryBuilder = boolQuery();
        queryBuilder.filter(termQuery("corpid.keyword", corpid));
        queryBuilder.filter(termsQuery("data." + RefundInstockEnum.REF_ID.getAttr(), idIn));
        queryBuilder.filter(termQuery("data." + RefundInstockEnum.TYPE.getAttr(), InstockTypeEnum.RED_CONTRACT_INSTOCK.getCode()));
        queryBuilder.filter(termQuery("del", 0));
        // 设置join_field
        queryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, IndexTypeEnum.IDX_SAAS_REFUND_INSTOCK.getType()));
        searchSourceBuilder.query(queryBuilder);
        List<PaasFormDataEntityExt> entityExts = paasEsModel.list(searchSourceBuilder, IndexTypeEnum.IDX_SAAS_REFUND_INSTOCK, Collections.singletonList(RefundInstockEnum.REF_ID.getAttr()), null, null);
        if (!Objects.equals(entityExts.size(), BasicConstant.ZERO)) {
            entityExts.forEach(item -> {
                Long refundId = item.getData().getLong(RefundInstockEnum.REF_ID.getAttr());
                refundIdList.add(refundId);
            });
            for (RefundEntityExt refundEntityExt : refundExtList) {
                if (refundIdList.contains(refundEntityExt.getId())) {
                    refundSerialNos.add(refundEntityExt.getSerialNo());
                }
            }
            throw new XbbException(RefundErrorCodeEnum.API_ERROR_215025, String.format(I18nMessageUtil.getMessage(RefundErrorCodeEnum.API_ERROR_215025.getMsg()), refundSerialNos.toString()));
        }
        try {
            if (!physicalDelIds.isEmpty()) {
                if(BasicConstant.ONE.equals(refundDeleteBatchDTO.getSingleFlag())
                        && BasicConstant.ONE.equals(idIn.size())){
                    paasEsModel.delete(physicalDelIds.get(0),corpid, IndexTypeEnum.IDX_SAAS_REFUND,null);
                }else {
                    // 删除es中存在，数据库不存在的数据
                    paasEsModel.deleteBatch(physicalDelIds, corpid, DelEnum.DELETE.getDel(), IndexTypeEnum.IDX_SAAS_REFUND);
                }
            }
            if (!deleteIdIn.isEmpty()) {
                if(BasicConstant.ONE.equals(refundDeleteBatchDTO.getSingleFlag())
                        && BasicConstant.ONE.equals(deleteIdIn.size())){
                    refundModel.deleteByKey(deleteIdIn.get(0),corpid);
                }else {
                    refundModel.deleteBatch(deleteIdIn, corpid, DelEnum.DELETE.getDel());
                }
                refundDeleteBatchVO.setDeleteIds(deleteIdIn);

                // 删除退货退款关联客户
                RefundUserDeleteBatchDTO refundUserDeleteBatchDTO = new RefundUserDeleteBatchDTO();
                BeanUtil.copyProperties(refundDeleteBatchDTO, refundUserDeleteBatchDTO);
                refundUserDeleteBatchDTO.setRefundIdIn(deleteIdIn);
                refundUserService.deleteBatch(refundUserDeleteBatchDTO);

                // 删除作废发票
                try {
                    refundInvoiceModel.deleteBatchByRefundIdIn(corpid, deleteIdIn);
                } catch (Exception e) {
                    LOG.error("删除退货退款关联作废发票失败：", e);
                    throw new XbbException(RefundErrorCodeEnum.API_ERROR_215028);
                }
                //序列号删除
                productSerialService.deleteSerial(corpid, deleteIdIn, XbbRefTypeEnum.REFUND.getCode());
            }
            ContractProductListVO redContractProductList = null;
            if (!redContractIdIn.isEmpty()) {

                // 删除合同业绩分配
                ContractPerformanceDeleteBatchDTO contractPerformanceDeleteBatchDTO = new ContractPerformanceDeleteBatchDTO();
                BeanUtil.copyProperties(refundDeleteBatchDTO, contractPerformanceDeleteBatchDTO, true);
                contractPerformanceDeleteBatchDTO.setContractIdIn(redContractIdIn);
                contractPerformanceService.deleteBatch(contractPerformanceDeleteBatchDTO);
                // 删除合同产品
                ContractProductDeleteBatchDTO contractProductDeleteBatchDTO = new ContractProductDeleteBatchDTO();
                BeanUtil.copyProperties(refundDeleteBatchDTO, contractProductDeleteBatchDTO, true);
                contractProductDeleteBatchDTO.setContractIdIn(redContractIdIn);
                //后面要用到 redContractProductList
                ContractProductListDTO contractProductListDTO = new ContractProductListDTO();
                contractProductListDTO.setCorpid(corpid);
                contractProductListDTO.setDel(DelEnum.NORMAL.getDel());
                contractProductListDTO.setContractIdIn(redContractIdIn);
                redContractProductList = contractProductService.findContractProductList(contractProductListDTO);
                contractProductService.deleteBatch(contractProductDeleteBatchDTO);
                // 合同那边的优化(删除红冲合同)
                try {
                    contractModel.deleteBatch(redContractIdIn, corpid);
                } catch (Exception e) {
                    LOG.error("删除退货退款关联红冲合同失败：", e);
                    throw new XbbException(RefundErrorCodeEnum.API_ERROR_215029);
                }
            }

            // 合同那边的优化(将原合同属性变更)
            if (!oldContractIdIn.isEmpty()) {
                // 查询合同还有没有关联的红冲合同
                for (Long contractId : oldContractIdIn) {
                    Map<String, Object> params = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    params.put(ParameterConstant.CORPID, corpid);
                    params.put(ParameterConstant.DEL, DelEnum.NORMAL.getDel());
                    List<PaasFormDataEntityExt> paasFormDataEntityExts = paasEsModel.selectByOneCondition(RedundantTemplateTypeEnum.REFUND.getCode(),
                            RefundEnum.CONTRACT_ID.getAttr(), contractId, params, IndexTypeEnum.IDX_SAAS_REFUND);
                    paasFormDataEntityExts.forEach((item) -> conId.add(item.getId()));
                }
                returnContractData(contractList, conId, contractOutstockProductMap, contractProductMap, contractIdAndCostMap, allContractCostMap);

                // TODO 海滨 更新原合同的退货数量
                //更改合同产品表的已退货数量,只有新合同才更改
                if(redContractProductList != null &&
                        !CollectionUtils.isEmpty(redContractProductList.getContractProductList())){
                    List<ContractProductEntity> contractProductList = redContractProductList.getContractProductList();
//                    退货退款何销售出库单都是老数据
                    Map<Long, Long> allOldredContractIdAndRefundId = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    for (ContractProductEntity contractProductEntity : contractProductList) {
                        Long key = contractProductEntity.getContractId();
                        if(Objects.isNull(contractProductEntity.getRefProductId())){
                            if (!allOldredContractIdAndRefundId.containsKey(key)) {
                                allOldredContractIdAndRefundId.put(key, redContractIdAndRefundId.getOrDefault(key, 0L));
                            }
                            redContractIdAndRefundId.remove(key);
                        }
                    }
                    //获取需要合并的红冲产品数据
                    Map<Long, Double> redProductNums = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    Map<Object, Double> oldRedProductNums = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                    HashSet<Long> allOldContractIds = new HashSet<>();
                    if(!redContractIdAndRefundId.isEmpty() || !allOldredContractIdAndRefundId.isEmpty()){
                        //行对应计算删除的产品数量
                        for (ContractProductEntity contractProductEntity : contractProductList) {
                            if(redContractIdAndRefundId.containsKey(contractProductEntity.getContractId())){
                                Long refProductId = contractProductEntity.getRefProductId();
                                Double num = Arith.add(redProductNums.get(refProductId)==null?0L:redProductNums.get(refProductId),
                                        contractProductEntity.getProductNum());
                                redProductNums.put(refProductId, num);
                             }else if (allOldredContractIdAndRefundId.containsKey(contractProductEntity.getContractId())){
//                               退货退款和销售出库单都是老数据
                                Long contractId = refundIdAndContractId.getOrDefault(allOldredContractIdAndRefundId.get(contractProductEntity.getContractId()), 0L);
                                String key = contractId + "" + contractProductEntity.getProductId();
                                Double num = oldRedProductNums.getOrDefault(key, 0D);
                                num += contractProductEntity.getProductNum();
                                oldRedProductNums.put(key, num);
                                allOldContractIds.add(contractId);
                            }
                         }
                    }
                    PaasAppEntity paasAppEntity = paasAppModel.getByAlias(XbbRefTypeEnum.JXC.getAlias(), corpid);
                    boolean isOpenJxc = false;
                    if (Objects.nonNull(paasAppEntity)) {
                        isOpenJxc = paasAppEntity.getEnable() == 1;
                    }
                    if (isOpenJxc) {
                        Map<String, Object> params = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                        params.put("corpid", corpid);
                        params.put("idIn", redProductNums.keySet());
                        params.put("del", DelEnum.NORMAL.getDel());
                        List<OutstockProductEntity> outstockProductEntities = outstockProductModel.findEntitys(params);
                        Map<Long, Double> refundNumsMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                        HashSet<Long> refOutProductIds = new HashSet<>();
                        if (!CollectionUtils.isEmpty(outstockProductEntities)) {
                            for (OutstockProductEntity outstockProductEntity : outstockProductEntities) {
                                Long id = outstockProductEntity.getId();
                                if (redProductNums.containsKey(id)) {
                                    if (Objects.isNull(outstockProductEntity.getRefProductId())) {
                                        refOutProductIds.add(id);
                                    }else {
                                        Double num = refundNumsMap.getOrDefault(outstockProductEntity.getRefProductId(), 0D);
                                        num += redProductNums.get(id);
                                        refundNumsMap.put(outstockProductEntity.getRefProductId(), num);
                                        //由于红冲合同产品数量是负数，所以此处应add
                                        outstockProductEntity.setInstockNum(Arith.add(outstockProductEntity.getInstockNum(), redProductNums.get(id)));
                                        outstockProductEntity.setUpdateTime(DateTimeUtil.getInt());
                                    }
                                }

                            }
                            //更新销售出库单产品的已入库数量
                            outstockProductModel.updateBatch(outstockProductEntities, corpid);
                        }
                        if (!refundNumsMap.isEmpty()) {
                            params.put("idIn", refundNumsMap.keySet());
                            List<ContractProductEntity> contractProductEntities = contractProductModel.findEntitys(params);
                            contractProductEntities.forEach(item -> {
                                if (refundNumsMap.containsKey(item.getId())) {
                                    //由于红冲合同产品数量是负数，所以此处应add
                                    item.setInstockNum(Arith.add(item.getInstockNum(), refundNumsMap.get(item.getId())));
                                }
                            });
                            contractProductModel.updateBatch(contractProductEntities, corpid);
                        }

                        if (!refOutProductIds.isEmpty()) {
//                            退货退款是新数据，出库单是老数据的情况
                            Map<Object, Double> refundProductNumsMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                            HashSet<Long> contractIds = new HashSet<>();
                            for (ContractProductEntity contractProductEntity : contractProductList) {
                                if(redContractIdAndRefundId.containsKey(contractProductEntity.getContractId())){
                                    Long refProductId = contractProductEntity.getRefProductId();
                                    if (refOutProductIds.contains(refProductId)) {
                                        Long refundId = redContractIdAndRefundId.get(contractProductEntity.getContractId());
                                        Long contractId = refundIdAndContractId.getOrDefault(refundId, 0L);
                                        contractIds.add(contractId);
                                        String key = contractId + "" + contractProductEntity.getProductId();
                                        Double num = refundProductNumsMap.getOrDefault(key, 0D);
                                        num += contractProductEntity.getProductNum();
                                        refundProductNumsMap.put(key, num);
                                    }
                                }
                            }
                            params.clear();
                            params.put("corpid", corpid);
                            params.put("contractIdIn", contractIds);
                            params.put("del", DelEnum.NORMAL.getDel());
                            List<ContractProductEntity> entitys = contractProductModel.findEntitys(params);
                            for (ContractProductEntity entity : entitys) {
                                String key = entity.getContractId() + "" + entity.getProductId();
                                Double amendNum = (-1) * refundProductNumsMap.getOrDefault(key, 0D);
                                Double instockNum ;
                                if (Arith.sub(entity.getInstockNum(), amendNum) > 0){
                                    instockNum = Arith.sub(entity.getInstockNum(), amendNum);
                                    refundProductNumsMap.remove(key);
                                }else {
                                    instockNum = 0D;
                                    refundProductNumsMap.put(key, Arith.sub(entity.getInstockNum(), amendNum));
                                }
                                entity.setInstockNum(instockNum);
                            }
                            contractProductModel.updateBatch(entitys, corpid);
                        }
                        if (!allOldContractIds.isEmpty()) {
//                            退货退款和销售出库都是老数据
                            params.clear();
                            params.put("corpid", corpid);
                            params.put("contractIdIn", allOldContractIds);
                            params.put("del", DelEnum.NORMAL.getDel());
                            List<ContractProductEntity> entitys = contractProductModel.findEntitys(params);
                            for (ContractProductEntity entity : entitys) {
                                String key = entity.getContractId() + "" + entity.getProductId();
                                Double amendNum = (-1) * oldRedProductNums.getOrDefault(key, 0D);
                                Double instockNum ;
                                if (Arith.sub(entity.getInstockNum(), amendNum) > 0){
                                    instockNum = Arith.sub(entity.getInstockNum(), amendNum);
                                    oldRedProductNums.remove(key);
                                }else {
                                    instockNum = 0D;
                                    oldRedProductNums.put(key, Arith.sub(entity.getInstockNum(), amendNum));
                                }
                                entity.setInstockNum(instockNum);
                            }
                            contractProductModel.updateBatch(entitys, corpid);
                        }
                    }else {
                        Map<String, Object> params = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                        params.put("corpid", corpid);
                        params.put("idIn", redProductNums.keySet());
                        params.put("del", DelEnum.NORMAL.getDel());
                        List<ContractProductEntity> contractProductEntityList = contractProductModel.findEntitys(params);
                        if (!CollectionUtils.isEmpty(contractProductEntityList)) {
                            for (ContractProductEntity contractProductEntity : contractProductEntityList) {
                                Long id = contractProductEntity.getId();
                                if (redProductNums.containsKey(id)) {
                                    //由于红冲合同产品数量是负数，所以此处应add
                                    contractProductEntity.setInstockNum(Arith.add(contractProductEntity.getInstockNum(), redProductNums.get(id)));
                                    contractProductEntity.setUpdateTime(DateTimeUtil.getInt());
                                }

                            }
                            //更新销售出库单产品的已入库数量
                            contractProductModel.updateBatch(contractProductEntityList, corpid);
                        }
                    }
                }
            }
            // TODO 删除相关审批记录
            // 退货退款删除回滚
        } catch (Exception e) {
            LOG.error("refundServiceImpl.deleteBatch 执行出错：", e);
            updateRollback(refundDeleteBatchDTO.getDataIdList(), corpid);
            redContractIdIn.addAll(oldContractIdIn);
            contractService.updateRollback(redContractIdIn, corpid);
            contractPerformanceService.updateRollbackByContractId(redContractIdIn, corpid);
            refundInvoiceModel.updateRollbackByRefundId(corpid, refundDeleteBatchDTO.getDataIdList());
            refundUserService.updateRollbackByRefundId(refundDeleteBatchDTO.getDataIdList(), corpid);

            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }

        //生成删除日志(区分单个删除和批量删除)
        String userId = refundDeleteBatchDTO.getUserId();
        String userName = refundDeleteBatchDTO.getLoginUserName();
        List<String> list = new ArrayList<>();
        Iterator<String> iterator = noAndName.keySet().iterator();
        while (iterator.hasNext()) {
            String key = iterator.next();
            String value = noAndName.get(key);
            if(StringUtil.isEmpty(value)){
                list.add(key);
            } else {
                StringBuilder sb = new StringBuilder();
                sb.append(key).append("（").append(value).append("）");
                list.add(sb.toString());
            }
        }
        String nameStr = StringUtils.join(list, "、");
        Integer singleFlag = refundDeleteBatchDTO.getSingleFlag();
        if(Objects.equals(0,singleFlag)||deleteIdIn.size() > 1){
            List<InfoArrPojo> infoArrPojoList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            InfoArrPojo infoArrPojo = new InfoArrPojo();
            infoArrPojo.setTitle(OperationLogHelp.setDetailTitle());
            infoArrPojo.setContent(nameStr);
            infoArrPojoList.add(infoArrPojo);
            DeleteBatchOperationLogDTO deleteBatchOperationLogDTO = new DeleteBatchOperationLogDTO( corpid,  userId,  userName, OperateModuleTypeEnum.REFUND,  OperateTypeEnum.DELETE,
                    null,  nameStr,  null,  deleteIdIn.size(),refundDeleteBatchDTO.getHttpHeader(),refundDeleteBatchDTO.getFormId(),refundDeleteBatchDTO.getBusinessType());
            OperationLogHandle operationLogHandle = operationLogFactory.getOperationLogHandle(SaasMarkEnum.SAAS.getCode(), XbbRefTypeEnum.REFUND.getCode());
            operationLogHandle.deleteBatch(infoArrPojoList,deleteBatchOperationLogDTO);
        } else if (Objects.equals(singleFlag, 1)&&CollectionsUtil.isNotEmpty(deleteIdIn)){
            DeleteOperationLogDTO deleteOperationLogDTO = new DeleteOperationLogDTO(corpid,userId,userName,OperateModuleTypeEnum.REFUND,OperateTypeEnum.DELETE,deleteIdIn.get(0).toString(),nameStr,null,refundDeleteBatchDTO.getHttpHeader(),refundDeleteBatchDTO.getFormId(),refundDeleteBatchDTO.getBusinessType());
            OperationLogHandle operationLogHandle = operationLogFactory.getOperationLogHandle(SaasMarkEnum.SAAS.getCode(), XbbRefTypeEnum.REFUND.getCode());
            operationLogHandle.delete(deleteOperationLogDTO);
        }


        try {
            // 动态
            if (!Objects.equals(DistributorMarkEnum.DISTRIBUTOR.getCode(), refundDeleteBatchDTO.getDistributorMark())) {
                DynamicStrategy dynamicStrategy = dynamicStrategyFactory.getDynamicStrategyByBusinessType(refundDeleteBatchDTO.getBusinessType());
                FormDataDeleteBatchDTO formDataDeleteBatchDTO = BeanUtil.copyProperties(refundDeleteBatchDTO, FormDataDeleteBatchDTO.class, true);
                List<PaasFormDataEntityExt> allowDeletePaasFormDatas = new ArrayList<>(refundExtList.size());
                BeanUtil.copyPropertiesList(refundExtList, allowDeletePaasFormDatas, PaasFormDataEntityExt.class, true);
                dynamicStrategy.batchDelete(DynamicDeleteDTO.initDynamicDeleteDTO(formDataDeleteBatchDTO, refundExtList.stream().map(RefundEntityExt::getId).collect(Collectors.toList()), allowDeletePaasFormDatas));
            }
        } catch (Exception e) {
            LOG.error("退货退库动态删除失败", e);
        }

        return refundDeleteBatchVO;
    }

    /**
     * 还原合同数据
     * @throws XbbException
     */
    public void returnContractData(List<ContractEntityExt> contractList, List<Long> conId, Map<Long, List<OutstockProductEntity>> contractOutstockProductMap,
                                    Map<Long, List<ContractProductEntity>> contractProductMap, Map<Long, Double> contractIdAndCostMap, Map<Long, Double> allContractCostMap) throws XbbException{
        List<UpdateDataEntity> updateDataList = new ArrayList<>();
        String corpid = "";
        for (ContractEntityExt contractEntityExt : contractList) {
            if (contractEntityExt != null) {
                JSONObject data = contractEntityExt.getData();
                JSONObject contractData = new JSONObject();
                Long contractId = contractEntityExt.getId();
                corpid = contractEntityExt.getCorpid();
                if(conId.isEmpty()){
                    contractData.put(ContractEnum.HAS_RED.getAttr(), BasicConstant.ZERO);
                }

                List<OutstockProductEntity> outstockProductList = contractOutstockProductMap.get(contractId);
                List<ContractProductEntity> contractProductList = contractProductMap.get(contractId);

                // 计算合同出库成本：SUM（已出库产品数量*出库产品成本）
                double realCost = 0D;
                boolean isOld = false;
                // 合并的出库产品数量MAP
                Map<Long, Double> outstockProductNumMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                // 行对应数量
                Map<Long, Double> lineProductNumMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                for (OutstockProductEntity outstockProductEntity : outstockProductList) {
                    if (Objects.isNull(outstockProductEntity.getRefProductId())) {
                        isOld = true;
                    }
                    Long productId = outstockProductEntity.getProductId();
                    Double productNum = outstockProductEntity.getProductNum();
                    productNum = productNum == null ? 0D : productNum;
                    Double cost = outstockProductEntity.getCost();
                    cost = cost == null ? 0D : cost;
                    realCost = Arith.add(realCost, Arith.mul(productNum, cost));
                    if (outstockProductNumMap.containsKey(productId)) {
                        outstockProductNumMap.put(productId, Arith.add(outstockProductNumMap.get(productId), productNum));
                    } else {
                        outstockProductNumMap.put(productId, productNum);
                    }
                    if (!isOld) {
                        Long refProductId = outstockProductEntity.getRefProductId();
                        if (lineProductNumMap.containsKey(refProductId)) {
                            lineProductNumMap.put(refProductId, Arith.add(lineProductNumMap.get(refProductId), productNum));
                        } else {
                            lineProductNumMap.put(refProductId, productNum);
                        }
                    }
                }

                // 算出合同中每种产品的平均价
                Map<Long, String> avgCostMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                for (ContractProductEntity contractProductEntity : contractProductList) {
                    Long productId = contractProductEntity.getProductId();
                    Double productNum = contractProductEntity.getProductNum() == null ? 0D : Math.abs(contractProductEntity.getProductNum());
                    if (isOld) {
                        if (avgCostMap.containsKey(productId)) {
                            // map中已经有相同产品，需要计算平均值
                            String productInfo = avgCostMap.get(productId);
                            String[] split = productInfo.split(",");
                            Double preCost = StringUtil.toDouble((split[0]), 0D);
                            Double preNum = StringUtil.toDouble((split[1]), 0D);
                            Double nowCost = SaasProductHelp.calculateCost(preNum, preCost, productNum, contractProductEntity.getCost(), 1);
                            Double nowNum = Arith.add(preNum, productNum);
                            avgCostMap.put(productId, nowCost + "," + nowNum);
                        } else {
                            // 将产品id为key，合同产品平均价和数量拼接字符串为value存入map中
                            String productInfo = contractProductEntity.getCost() + "," + productNum;
                            avgCostMap.put(productId, productInfo);
                        }
                    } else if (lineProductNumMap.containsKey(contractProductEntity.getId())) {
                        // 分行已出库数量计算
                        contractProductEntity.setContractOutstockNum(lineProductNumMap.get(contractProductEntity.getId()));
                    }
                }
                double estimateCost = 0D;
                if (isOld) {
                    // 老数据合同预估成本计算
                    for (ContractProductEntity contractProductEntity : contractProductList) {
                        String productInfo = avgCostMap.get(contractProductEntity.getProductId());
                        if (org.apache.commons.lang.StringUtils.isEmpty(productInfo)) {
                            continue;
                        }
                        String[] productInfos = productInfo.split(",");
                        if (outstockProductNumMap.containsKey(contractProductEntity.getProductId())) {
                            if (Arith.sub(contractProductEntity.getProductNum(), outstockProductNumMap.get(contractProductEntity.getProductId())) > 0) {
                                estimateCost = Arith.add(estimateCost, Arith.mul(Arith.sub(contractProductEntity.getProductNum(), outstockProductNumMap.get(contractProductEntity.getProductId())), StringUtil.toDouble((productInfos[0]), 0D)));
                            }
                        } else {
                            estimateCost = Arith.add(estimateCost, Arith.mul(contractProductEntity.getProductNum(), StringUtil.toDouble((productInfos[0]), 0D)));
                        }
                    }
                } else {
                    // 新数据合同预估成本计算
                    for (ContractProductEntity contractProductEntity : contractProductList) {
                        if (Arith.sub(contractProductEntity.getProductNum(), contractProductEntity.getContractOutstockNum()) > 0) {
                            estimateCost = Arith.add(estimateCost, Arith.mul(contractProductEntity.getCost(), Arith.sub(contractProductEntity.getProductNum(), contractProductEntity.getContractOutstockNum())));
                        }
                    }
                }

                Double surchargeAmount = getDoubleOrDefaultFromFormData(data, ContractEnum.OTHER_EXPENSE.getAttr(), BasicConstant.ZERO_DOUBLE);
                Double contractCost;
                if(contractIdAndCostMap.containsKey(contractId)){
                    Double cost = contractIdAndCostMap.get(contractId) == null ? BasicConstant.ZERO_DOUBLE : contractIdAndCostMap.get(contractId);
                    contractCost = Arith.sub(Arith.add(Arith.add(estimateCost, realCost), surchargeAmount), cost);
                } else {
                    contractCost = Arith.add(Arith.add(estimateCost, realCost), surchargeAmount);
                }
                // 合同成本 = 合同产品成本 - 退货产品成本（入库单的产品成本：新数据用入库单的成本，旧数据用出库单的平均成本）+ 其他费用
                contractData.put(ContractEnum.CONTRACT_COST.getAttr(), Arith.round(contractCost, 2));

                //合同毛利 = 合同金额 - 退货金额（关联计算）- 合同成本（同上）
                Double amount = getDoubleOrDefaultFromFormData(data, ContractEnum.AMOUNT.getAttr(), 0D);
                Double grossProfit;
                if(allContractCostMap.containsKey(contractId)){
                    Double cost = allContractCostMap.get(contractId) == null ? BasicConstant.ZERO_DOUBLE : allContractCostMap.get(contractId);
                    grossProfit = Arith.sub(Arith.sub(amount, contractCost), cost);
                } else {
                    grossProfit = Arith.sub(amount, contractCost);
                }
                contractData.put(ContractEnum.GROSS_PROFIT.getAttr(), Arith.round(grossProfit, 2));
                // 合同毛利率
                if (Double.compare(amount, BasicConstant.ZERO_DOUBLE) != 0) {
                    contractData.put(ContractEnum.GROSS_PROFIT_RATE.getAttr(), Arith.round(Arith.div(grossProfit, amount), 4));
                } else {
                    contractData.put(ContractEnum.GROSS_PROFIT_RATE.getAttr(), BasicConstant.ZERO_DOUBLE);
                }

                // 现金毛利 = 合同已收款金额 - 合同成本（同上）
                Double finishAmount = getDoubleOrDefaultFromFormData(data, ContractEnum.FINISH_AMOUNT.getAttr(), 0D);
                Double cashProfit = Arith.sub(finishAmount, contractCost);
                contractData.put(ContractEnum.CASH_PROFIT.getAttr(), cashProfit);
                // 现金毛利率
                if (Double.compare(finishAmount, BasicConstant.ZERO_DOUBLE) != 0) {
                    contractData.put(ContractEnum.CASH_PROFIT_RATE.getAttr(), Arith.round(Arith.div(cashProfit, finishAmount), 2));
                } else {
                    contractData.put(ContractEnum.CASH_PROFIT_RATE.getAttr(), BasicConstant.ZERO_DOUBLE);
                }
                UpdateDataEntity updateDataEntity = ExplainUtil.getUpdateData(contractEntityExt.getId(), contractData, contractEntityExt.getCorpid());
                updateDataList.add(updateDataEntity);
            }
        }
        if (CollectionsUtil.isNotEmpty(updateDataList) && StringUtil.isNotEmpty(corpid)) {
            contractModel.updateBatch(updateDataList, corpid);
        }
    }

    /**
     * 更新时回滚
     * @param idIn
     * @param corpid
     * @throws XbbException
     */
    public void updateRollback(List<Long> idIn, String corpid) throws XbbException {
        if (Objects.isNull(idIn) || idIn.isEmpty()) {
            return;
        }
        Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        param.put("idIn", idIn);
        param.put(StringConstant.CORPID, corpid);
        List<RefundEntityExt> refundList = refundModel.findEntitysWithoutSub(param);
        if (Objects.nonNull(refundList)) {
            for (RefundEntityExt item : refundList) {
                PaasFormDataEntity paasFormDataEntity = new PaasFormDataEntity();
                BeanUtil.copyProperties(item, paasFormDataEntity);
                proEsHelper.reductionEsInUpdate(paasFormDataEntity, item.getId(), corpid, IndexTypeEnum.IDX_SAAS_REFUND);
            }
        }
    }

    /**
     * 之前是获取产品金额，获取退货退款的退货金额（特殊处理）
     *
     * @param businessProductListDTO
     * @return
     */
    @Override
    public RefundAmountVO getRefundAmount(BusinessProductListDTO businessProductListDTO) throws XbbException {
        RefundAmountVO refundAmountVO = new RefundAmountVO();
        Double returnAmount = BasicConstant.ZERO_DOUBLE;
        String corpid = businessProductListDTO.getCorpid();
        Long contractId = businessProductListDTO.getDataId();
        PaasFormDataEntityExt customerEntity = contractModel.getByKey(contractId, corpid);
        JSONObject customerData = customerEntity.getData();
        if(customerData != null){
            Double amount = getDoubleOrDefaultFromFormData(customerData, ContractEnum.AMOUNT.getAttr(), BasicConstant.ZERO_DOUBLE);
            Double refundAmount = getRefundReturnAmount(corpid, contractId);
            Double goodsAmount = Arith.sub(Math.abs(amount), refundAmount);
            Double totalAmount = goodsAmount > 0 ? goodsAmount : BasicConstant.ZERO_DOUBLE;
            returnAmount = totalAmount;
        }
        String attr = RefundEnum.RETURN_AMOUNT.getAttr();
        refundAmountVO.setAttr(attr);
        refundAmountVO.setReturnAmount(returnAmount);
        return refundAmountVO;
    }

    @Override
    public void formatExportValue(List<PaasFormDataEntityExt> paasFormDataESList, FormDataListDTO formDataListDTO, List<FieldAttrEntityForImport> fieldAttrList) throws XbbException {
        List<Long> businessIdIn = new ArrayList<>();
        paasFormDataESList.forEach(paasFormDataEntityExt -> businessIdIn.add(paasFormDataEntityExt.getData().getLong(RefundEnum.RED_CONTRACT_ID.getAttr())));
        List<ContractProductEntity> contractProductByContractIdIn = contractProductModel.getContractProductByContractIdIn(formDataListDTO.getCorpid(), businessIdIn);
        Map<Long, List<ContractProductEntity>> productMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        List<Long> productIdIn = new ArrayList<>();
        contractProductByContractIdIn.forEach(contractProductEntity -> {
            List<ContractProductEntity> productEntityList = new ArrayList<>();
            if (productMap.containsKey(contractProductEntity.getContractId())) {
                productEntityList.addAll(productMap.get(contractProductEntity.getContractId()));
            }
            productEntityList.add(contractProductEntity);
            productMap.put(contractProductEntity.getContractId(), productEntityList);
            productIdIn.add(contractProductEntity.getProductId());
        });
        List<ProductEntityExt> productList = productModel.getProductListByIdIn(formDataListDTO.getCorpid(), productIdIn, 0);
        Map<Long, ProductEntityExt> productsMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        productList.forEach(item -> productsMap.put(item.getId(), item));

        Map<String, MultiUnitItemPoJo> groupBaseUnitStringMap = relativeProductHelp.getGroupBaseUnitStringMap(formDataListDTO.getCorpid());
        for (PaasFormDataEntityExt paasFormDataEntityExt : paasFormDataESList) {
            JSONObject data = paasFormDataEntityExt.getData();
            List<ContractProductEntity> singleContractProductEntityList = productMap.getOrDefault(paasFormDataEntityExt.getData().getLong(RefundEnum.RED_CONTRACT_ID.getAttr()), new ArrayList<>());
            JSONArray productArray = new JSONArray();
            for (ContractProductEntity entity : singleContractProductEntityList) {
                ProductEntityExt productEntityExt = productsMap.getOrDefault(entity.getProductId(), new ProductEntityExt());
                JSONObject productData = new JSONObject();
                if(Objects.nonNull(productEntityExt.getData())){
                    productData = productEntityExt.getData();
                }
                JSONObject productItemObj = new JSONObject();
                if (Objects.nonNull(entity.getPriceData()) && entity.getPriceData().size() > 0) {
                    entity.getData().putAll(entity.getPriceData());
                }
                if (Objects.nonNull(entity.getData())) {
                    productItemObj.putAll(entity.getData());
                }
                productItemObj.put(SelectProductEnum.PRODUCT_NAME.getAttr(), entity.getProductName());
                productItemObj.put(SelectProductEnum.PRODUCT_NO.getAttr(), entity.getProductNo());
                productItemObj.put(SelectProductEnum.SPECIFICATION.getAttr(), entity.getSpecification());
                productItemObj.put(SelectProductEnum.BARCODE.getAttr(), entity.getBarcode());
                productItemObj.put(RefundProductEnum.PRICE.getAttr(), entity.getPrice());
                productItemObj.put(RefundProductEnum.NUM.getAttr(), Math.abs(entity.getProductNum()));
                productItemObj.put(RefundProductEnum.MEMO.getAttr(), entity.getMemo());
                productItemObj.put(RefundProductEnum.INSTOCK_NUM.getAttr(), entity.getInstockNum());
                productItemObj.put(RefundProductEnum.WAIT_INSTOCK_NUM.getAttr(), Arith.sub(Math.abs(entity.getProductNum()), entity.getInstockNum()));
                productItemObj.put(SelectProductEnum.UNIT.getAttr(), productData.get(ProductEnum.UNIT.getAttr()));
                productItemObj.put(ProductEnum.ENABLE_MULTI_UNIT.getAttr(), productData.getIntValue(ProductEnum.ENABLE_MULTI_UNIT.getAttr()));
                if (Objects.nonNull(productItemObj.get(SelectProductEnum.PRODUCE_DATE.getAttr()))) {
                    Long guaranteePeriod = productItemObj.getLong(SelectProductEnum.PRODUCE_DATE.getAttr());
                    String produceDateStr = DateTimeUtil.getStringEpochSecond(guaranteePeriod, DateTimeUtil.SDFDate);
                    productItemObj.put(SelectProductEnum.PRODUCE_DATE.getAttr(), produceDateStr);
                }
                //到期日期格式转换
                Long expireDate = productItemObj.getLong(SelectProductEnum.EXPIRE_DATE.getAttr());
                if (Objects.nonNull(expireDate)){
                    if (expireDate == 0L) {
                        productItemObj.put(SelectProductEnum.EXPIRE_DATE.getAttr(), "");
                    } else {
                        String expireDateStr = DateTimeUtil.getStringEpochSecond(expireDate, DateTimeUtil.SDFDate);
                        productItemObj.put(SelectProductEnum.EXPIRE_DATE.getAttr(), expireDateStr);
                    }
                }
                //基本单位时直接塞入productUnit
                if (Objects.isNull(entity.getBusinessUnit())){
                    if (Objects.equals(productItemObj.getInteger(ProductEnum.ENABLE_MULTI_UNIT.getAttr()), BasicConstant.ONE)){
                        productItemObj.put(ProductEnum.UNIT.getAttr(), groupBaseUnitStringMap.getOrDefault(productItemObj.getString(ProductEnum.UNIT.getAttr()), new MultiUnitItemPoJo()).getBaseValue());
                        entity.setProductUnit(productItemObj.getString(ProductEnum.UNIT.getAttr()));
                    }
                    productItemObj.put(SelectProductEnum.NUM.getAttr(), Math.abs(entity.getProductNum()));
                    productItemObj.put(RefundProductEnum.SUBTOTAL.getAttr(), Arith.mul(entity.getPrice(), Math.abs(entity.getProductNum())));
                } else {
                    productItemObj.put(ProductEnum.UNIT.getAttr(), entity.getBusinessUnit());
                    productItemObj.put(SelectProductEnum.NUM.getAttr(),Math.abs(entity.getBusinessNum()));
                    productItemObj.put(RefundProductEnum.SUBTOTAL.getAttr(), Arith.mul(entity.getData().getDouble(SelectProductEnum.PRICE.getAttr()), Math.abs(entity.getBusinessNum())));
                    productItemObj.put(RefundProductEnum.INSTOCK_NUM.getAttr(), Arith.div(entity.getInstockNum(), entity.getRate()));
                    productItemObj.put(RefundProductEnum.WAIT_INSTOCK_NUM.getAttr(), Arith.sub(Math.abs(entity.getBusinessNum()), Arith.div(entity.getInstockNum(), entity.getRate())));
                    productItemObj.put(RefundProductEnum.PRICE.getAttr(), entity.getPriceData().get(RefundProductEnum.PRICE.getAttr()));
                }

                if(Objects.equals(productItemObj.getInteger(ProductEnum.ENABLE_MULTI_UNIT.getAttr()), BasicConstant.ONE)){
                    productItemObj.put(SelectProductEnum.BASIC_UNIT.getAttr(), entity.getProductUnit());
                    productItemObj.put(SelectProductEnum.BASIC_UNIT_NUM.getAttr(),  Math.abs(entity.getProductNum()));
                } else {
                    productItemObj.put(SelectProductEnum.BASIC_UNIT.getAttr(), "");
                    productItemObj.put(SelectProductEnum.BASIC_UNIT_NUM.getAttr(), "");
                }
                productArray.add(productItemObj);
            }
            data.put(RefundEnum.PRODUCTS.getAttr(), productArray);
        }
    }

    /**
     * 批量编辑
     *
     * @param refundEditAttrUpdateDTO
     * @return com.xbongbong.pro.suppliercontact.pojo.vo.RefundEditAttrUpdateVO
     * @throws XbbException 业务异常
     * @author 陈有利
     * @date 2019/6/7 16:45
     */
    @Override
    public RefundEditAttrUpdateVO batchEditAttr(RefundEditAttrUpdateDTO refundEditAttrUpdateDTO) throws XbbException {
        String userId = refundEditAttrUpdateDTO.getUserId();
        String corpid = refundEditAttrUpdateDTO.getCorpid();
        String loginUserName = refundEditAttrUpdateDTO.getLoginUserName();
        Integer isBatch = refundEditAttrUpdateDTO.getIsBatch();
        RefundEditAttrUpdateVO refundEditAttrUpdateVO = new RefundEditAttrUpdateVO();
        Integer saasMark = refundEditAttrUpdateDTO.getSaasMark();
        Integer businessType = refundEditAttrUpdateDTO.getBusinessType();
        Long formId = refundEditAttrUpdateDTO.getFormId();
        List<RefundEntityExt> refundEntityList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        Map<String, Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        param.put("corpid", refundEditAttrUpdateDTO.getCorpid());
        param.put("idIn", refundEditAttrUpdateDTO.getDataIdList());
        try {
            List<Long> idIn = refundEditAttrUpdateDTO.getDataIdList();
            List<RefundUpdateDTO> refundUpdateDTOS = new ArrayList<>();
            idIn.forEach((item)->{
                RefundUpdateDTO refundUpdateDTO = new RefundUpdateDTO();
                refundUpdateDTO.setId(item);
                JSONObject data = ProSaveHelp.getBatchUpdateData(refundEditAttrUpdateDTO.getFieldEditedList());
                refundUpdateDTO.setData(data);
                refundUpdateDTOS.add(refundUpdateDTO);
            });
            if (!refundUpdateDTOS.isEmpty()) {
                refundEntityList = refundModel.findEntitys(param);
                if (Objects.isNull(refundEntityList)){
                    throw new XbbException(SystemErrorCodeEnum.API_ERROR_100018);
                }
                //权限团队校验前置了
                List<Long> errorIdList = new ArrayList<>();
//                List<Long> errorIdList = userTeamHelp.batchTeamMembersCheckEditPermission(refundEditAttrUpdateDTO.getBusinessType(), refundEditAttrUpdateDTO.getSaasMark(),
//                        refundEditAttrUpdateDTO.getMenuId(), refundEditAttrUpdateDTO.getLoginUser(), refundEditAttrUpdateDTO.getDistributorMark(),
//                        refundEditAttrUpdateDTO.getDataIdList(), new HashMap<>());
                List<String> errorNameList = new ArrayList<>();
                for (RefundEntityExt refundEntityExt : refundEntityList) {
                    if (errorIdList.contains(refundEntityExt.getId())) {
                        errorNameList.add(refundEntityExt.getData().getString(RefundEnum.REFUND_NAME.getAttr()));
                    }
                }
                String nameStr = org.apache.commons.lang.StringUtils.join(errorNameList, "、");
                if (CollectionUtils.isNotEmpty(errorNameList)) {
                    throw new XbbException(UserTeamErrorCodeEnum.API_ERROR_271038.getCode(), String.format(UserTeamErrorCodeEnum.API_ERROR_271038.getMsg(), nameStr));
                }
                RefundUpdateBatchDTO refundUpdateBatchDTO = new RefundUpdateBatchDTO();
                BeanUtil.copyProperties(refundEditAttrUpdateDTO, refundUpdateBatchDTO);
                refundUpdateBatchDTO.setRefundUpdateList(refundUpdateDTOS);
                updateBatch(refundUpdateBatchDTO);
            }
            // 批量编辑日志
            List<Long> dataIdList = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            for (RefundEntityExt item : refundEntityList) {
                dataIdList.add(item.getId());
            }
            if(Objects.nonNull(isBatch)){
                List<RefundEntityExt> newRefundEntityList = refundModel.findEntitys(param);
                List<PaasFormDataEntity> newDataList = new ArrayList<>();
                List<PaasFormDataEntity> oldDataList = new ArrayList<>();
                BeanUtil.copyPropertiesList(refundEntityList,oldDataList,PaasFormDataEntity.class);
                BeanUtil.copyPropertiesList(newRefundEntityList,newDataList,PaasFormDataEntity.class);
                OperationLogHandle operationLogHandle = operationLogFactory.getOperationLogHandle(saasMark,businessType);
                UpdateBatchOperationLogDTO updateBatchOperationLogDTO = new UpdateBatchOperationLogDTO(corpid, userId, loginUserName, dataIdList.size(), refundEditAttrUpdateDTO.getHttpHeader(),
                        refundEditAttrUpdateDTO.getLogFieldEditedList(), newDataList, oldDataList, formId, businessType, isBatch);;
                operationLogHandle.updateBatch(updateBatchOperationLogDTO);
            }
        } catch (XbbException e) {
            throw e;
        } catch (Exception e) {
            LOG.error("refundServiceImpl.batchEditAttr 执行出错：", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
        }
        return refundEditAttrUpdateVO;
    }

    @Override
    public FormDataAddDTO formatExcelValue(ImportFormDataDTO importFormDataDTO, List<CellTitlePojo> titlePojoList, RowGroupPojo rowGroupPojo, List<FieldAttrEntityForImport> fieldAttrList) throws XbbException{
        FormDataAddDTO formDataAddDTO = new FormDataAddDTO();
        BeanUtil.copyProperties(importFormDataDTO, formDataAddDTO);
        formDataAddDTO.setSerialNo("");
        JSONObject dataJson = new JSONObject();
        List<List<CellValuePojo>> rowValueList = rowGroupPojo.getRowValueList();
        // 分组的第一条数据作为给实体对象赋值的数据
        List<CellValuePojo> cellValueList = rowValueList.get(0);
        Long contractId = 0L;
        Long linkCustomerId = 0L;
        Double sheetAmount = 0D;
        String corpid = importFormDataDTO.getCorpid();

        FieldAttrEntityForImport linkCustomerIdAttr = null;
        FieldAttrEntityForImport linkContractIdAttr = null;
        for (FieldAttrEntityForImport fieldAttrEntityForImport : fieldAttrList) {
            if (Objects.equals(fieldAttrEntityForImport.getAttr(), RefundEnum.CUSTOMER_ID.getAttr())) {
                linkCustomerIdAttr = fieldAttrEntityForImport;
            } else if (Objects.equals(fieldAttrEntityForImport.getAttr(), RefundEnum.CONTRACT_ID.getAttr())) {
                linkContractIdAttr = fieldAttrEntityForImport;
            }
        }
        if (Objects.nonNull(linkCustomerIdAttr)) {
            linkCustomerId = importHelper.formatLinkCustomer2CustomerId(titlePojoList, dataJson, rowValueList, linkCustomerIdAttr);
            if (Objects.equals(linkCustomerId, 0L)) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028, ErrorMessageConstant.PLEASE_ENTER, linkCustomerIdAttr.getAttrName());
            }
        }
        if (Objects.nonNull(linkContractIdAttr) && !Objects.equals(linkCustomerId, 0L)) {
            Integer columnIndex = importHelper.getColumnIndexByTitle(titlePojoList, linkContractIdAttr.getAttrName(), null);
            Object cellValue = importHelper.getValueByColumnIndex(cellValueList, columnIndex);
            contractId = importHelper.formatRelyBusiness(linkCustomerId, dataJson, linkContractIdAttr, cellValue, ContractEnum.LINK_CUSTOMER.getAttr());
        }


        for (FieldAttrEntityForImport fieldAttr : fieldAttrList) {
            String attr = fieldAttr.getAttr();
            Integer fieldType = fieldAttr.getFieldType();
            String attrName = fieldAttr.getAttrName();
            Integer columnIndex = importHelper.getColumnIndexByTitle(titlePojoList, attrName, null);
            Object cellValue = importHelper.getValueByColumnIndex(cellValueList, columnIndex);
            if (Objects.equals(attr, RefundEnum.PRODUCTS.getAttr())) {
                importHelper.formatCommonProduct(titlePojoList, dataJson, rowValueList, fieldAttr, XbbRefTypeEnum.REFUND.getCode(), corpid);
            } else if (Objects.equals(attr, RefundEnum.CUSTOMER_ID.getAttr())) {

            } else if (Objects.equals(fieldType, FieldTypeEnum.SUB_FORM.getType())) {
                importHelper.formatSubFormValue4Import(rowValueList, titlePojoList, importFormDataDTO, fieldAttr, dataJson);
            } else {
                if (Objects.isNull(cellValue) || StringUtil.isEmpty(cellValue.toString())) {
                    continue;
                }
                if (ImportHelper.commonHandleFieldType.contains(fieldAttr.getFieldType())) {
                    importHelper.formatCommonField(dataJson, fieldAttr, cellValue);
                } else {
                    if (Objects.equals(attr, RefundEnum.CONTRACT_ID.getAttr())) {

                    } else if (Objects.equals(attr, RefundEnum.PAYMENT_SHEETS.getAttr())) {
                        List<PaasFormDataEntityExt> paymentSheets = importHelper.formatMultiRelyBusiness(contractId, dataJson, fieldAttr, cellValue, PaymentSheetEnum.CONTRACT.getAttr());
                        sheetAmount = 0D;
                        for (PaasFormDataEntityExt paasFormDataEntityExt : paymentSheets) {
                            sheetAmount += getDoubleOrDefaultFromFormData(paasFormDataEntityExt.getData(), PaymentSheetEnum.AMOUNT.getAttr(), 0D);
                        }
                        dataJson.put(RefundEnum.REFUND_AMOUNT.getAttr(), sheetAmount);
                    } else if (Objects.equals(attr, RefundEnum.PAYMENTS.getAttr())) {
                        importHelper.formatMultiRelyBusiness(contractId, dataJson, fieldAttr, cellValue, PaymentEnum.CONTRACT.getAttr());
                    } else if (Objects.equals(attr, RefundEnum.INVOICES.getAttr())) {
                        importHelper.formatMultiRelyBusiness(contractId, dataJson, fieldAttr, cellValue, InvoiceEnum.CONTRACT_ID.getAttr());
                    } else if (Objects.equals(fieldType, FieldTypeEnum.SERIALNO.getType())) {
                        formDataAddDTO.setSerialNo(cellValue.toString());
                    } else if (Objects.equals(fieldType, FieldTypeEnum.LINK_DATA.getType())) {
                        importHelper.formatLinkData(cellValue, fieldAttr, dataJson);
                    } else if (Objects.equals(fieldType, FieldTypeEnum.LINK_DATA_MULTI.getType())) {
                        importHelper.formatLinkDataMulti(cellValue, importFormDataDTO, fieldAttr, dataJson);
                    } else {
                        dataJson.put(attr, cellValue);
                    }
                }
            }
        }
        formDataAddDTO.setDataList(dataJson);
        return formDataAddDTO;
    }

    /**
     * 关联新建格式化解释
     *
     * @param handlerExplainInLinkItemDTO 入参
     * @throws XbbException 异常
     */
    @Override
    public void formatLinkAddExplain(HandlerExplainInLinkItemDTO handlerExplainInLinkItemDTO) throws XbbException {
        JSONObject linkFormData = handlerExplainInLinkItemDTO.getLinkFormData();
        Long linkDataId = handlerExplainInLinkItemDTO.getLinkDataId();
        List<FieldAttrEntity> explainList = handlerExplainInLinkItemDTO.getExplainList();
        PaasFormDataEntityExt paasFormDataEntityExt = handlerExplainInLinkItemDTO.getPaasFormDataEntityExt();
        String corpid = paasFormDataEntityExt.getCorpid();
        FieldAttrEntity linkCustomerField = new FieldAttrEntity();
        FieldAttrEntity linkContractField = new FieldAttrEntity();
        FieldAttrEntity returnAmountField = new FieldAttrEntity();
        FieldAttrEntity productField = new FieldAttrEntity();
        for (FieldAttrEntity fieldAttrEntity : explainList) {
            if (Objects.equals(fieldAttrEntity.getAttr(), RefundEnum.CUSTOMER_ID.getAttr())) {
                linkCustomerField = fieldAttrEntity;
            }
            if (Objects.equals(fieldAttrEntity.getAttr(), RefundEnum.CONTRACT_ID.getAttr())) {
                linkContractField = fieldAttrEntity;
            }
            if (Objects.equals(fieldAttrEntity.getAttr(), RefundEnum.RETURN_AMOUNT.getAttr())) {
                returnAmountField = fieldAttrEntity;
            }
            if (Objects.equals(fieldAttrEntity.getAttr(), RefundEnum.PRODUCTS.getAttr())) {
                productField = fieldAttrEntity;
            }
        }
        Integer businessType = handlerExplainInLinkItemDTO.getLinkBusinessType();
        RedundantTemplateTypeEnum redundantTemplateTypeEnum = RedundantTemplateTypeEnum.getByCode(businessType);
        switch (redundantTemplateTypeEnum) {
            case CUSTOMER:
                String customerName = FastJsonHelper.getStringOrDefaultFromFormData(linkFormData, CustomerManagementEnum.NAME.getAttr(), "");
                linkCustomerField.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(linkDataId, customerName));
                break;
            case CONTRACT:
                String contractNo = paasFormDataEntityExt.getSerialNo();
                Map<String,Object> map = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
                map.put(ContractEnum.AMOUNT.getAttr(), getDoubleOrDefaultFromFormData(linkFormData, ContractEnum.AMOUNT.getAttr(), 0D));
                map.put(StringConstant.FORM_ID, handlerExplainInLinkItemDTO.getSourceFormId());
                linkContractField.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(linkDataId, contractNo, map));
                JSONArray linkCustomerArr = FastJsonHelper.getJsonArrOrDefaultFromFormData(linkFormData, ContractEnum.LINK_CUSTOMER.getAttr(), new JSONArray());
                linkCustomerField.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(linkCustomerArr));
                //linkContractField.setDefaultAttr(saasUpdateHelp.getDefaultAttrPojo(linkDataId, paasFormDataEntityExt.getSerialNo()));


                JSONObject productData = new JSONObject();
                String linkAttr = formmatRefundProduct4Show(linkDataId,corpid,productData);

                JSONArray productArray = formDataValidateProductHelp.otherProductToAnother(productData,productField,RefundEnum.PRODUCTS.getAttr(),linkAttr,corpid, handlerExplainInLinkItemDTO.getLoginUser(), handlerExplainInLinkItemDTO.getBusinessType(), handlerExplainInLinkItemDTO.getLinkBusinessType());
                //productField.setDefaultAttr(saasUpdateHelp.setDefaultValue(productArray));
                Double totalAmount = 0D;
                if (!productArray.isEmpty()){
                    for (int i = 0;i < productArray.size();i++){
                        JSONObject jsonObject = productArray.getJSONObject(i);
                        Double num = jsonObject.getDouble(SelectProductEnum.NUM.getAttr());
                        Double price = jsonObject.getDouble(SelectProductEnum.PRICE.getAttr());
                        totalAmount += Arith.mul(num,price);
                    }
                }else {
                    Double amount = getDoubleOrDefaultFromFormData(linkFormData, ContractEnum.AMOUNT.getAttr(), BasicConstant.ZERO_DOUBLE);
                    Double refundAmount = getRefundReturnAmount(corpid, linkDataId);
                    Double goodsAmount = Arith.sub(amount, refundAmount);
                    totalAmount = goodsAmount > 0 ? goodsAmount : BasicConstant.ZERO_DOUBLE;
                }
                DefaultAttrPoJo returnAmountPojo = returnAmountField.getDefaultAttr();
                returnAmountPojo.setUseLinkValue(BasicConstant.ONE);
                returnAmountPojo.setLinkFormValue(totalAmount);
                returnAmountField.setDefaultAttr(returnAmountPojo);
//                BusinessProductListDTO businessProductListDTO = new BusinessProductListDTO();
//                BeanUtil.copyProperties(paasFormDataEntityExt, businessProductListDTO);
//                BeanUtil.copyProperties(handlerExplainInLinkItemDTO, businessProductListDTO);
//                businessProductListDTO.setSourceBusinessType(XbbRefTypeEnum.REFUND.getCode());
//                businessProductListDTO.setDataId(linkDataId);
//                businessProductListDTO.setBusinessType(businessType);
//                // 合同快速新建退货退款时将产品带到列表
//                BusinessProductListVO businessProductListVO = businessProductService.getBusinessProductList(businessProductListDTO);
//                JSONObject productData = new JSONObject();
//                contractService.formatReturnProduct4Show2(corpid,linkDataId,productData);
//                JSONObject product = businessProductListVO.getProduct();
//                if(!Objects.equals(product, null)){
//                    JSONObject others = product.getJSONObject(BusinessConstant.OTHERS);
//                    JSONArray productList = product.getJSONArray(StringConstant.PRODUCT_LIST);
//                    if (!others.isEmpty()) {
//                        DefaultAttrPoJo defaultAttr;
//                        defaultAttr = productList.size() != 0 ? saasUpdateHelp.setDefaultValue(others.getDouble(BusinessConstant.TOTAL_PRODUCT_MONEY)) : saasUpdateHelp.setDefaultValue(totalAmount);
//                        returnAmountField.setDefaultAttr(defaultAttr);
//                    }
//                    productField.setDefaultAttr(saasUpdateHelp.setDefaultValue(product));
//                } else {
//                    productField.setDefaultAttr(new DefaultAttrPoJo());
//                }
                break;
            default:
                break;
        }
    }

    public String formmatRefundProduct4Show(Long contractId, String corpid, JSONObject productData) throws XbbException {
        PaasAppEntity paasAppEntity = paasAppModel.getByAlias(XbbRefTypeEnum.JXC.getAlias(), corpid);
        boolean isOpenJxc = false;
        if (Objects.nonNull(paasAppEntity)) {
            isOpenJxc = paasAppEntity.getEnable() == 1;
        }
        if (isOpenJxc){
            List<ContractProductEntity> contractProductEntityList = contractProductModel.getContractCost(contractId,corpid);
            Map<Long,Double> costMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            contractProductEntityList.forEach(item -> costMap.put(item.getProductId(),item.getPrice()));
            List<OutstockProductEntity> outstockProductEntityList = formDataValidateProductHelp.searchContractUnRefund(corpid,contractId,true, null);
            outstockService.formatProduct4Show3(new HashMap<>(), new HashMap<>(), new HashMap<>(), outstockProductEntityList,productData,UpdateDataTypeEnum.LINK_ADD,null, null);
            JSONArray jsonArray = productData.getJSONArray(OutstockEnum.PRODUCT.getAttr());
            //额外拿一下合同产品数据
            for (int i = 0;i < jsonArray.size();i++){
                JSONObject jsonObject = jsonArray.getJSONObject(i);
                Long productId = jsonObject.getLong(SelectProductEnum.PRODUCT.getAttr());
                jsonObject.put(RefundProductEnum.PRICE.getAttr(),costMap.getOrDefault(productId,0D));
                jsonObject.put(RefundProductEnum.SUBTOTAL.getAttr(),jsonObject.getDouble(RefundProductEnum.PRICE.getAttr()) * jsonObject.getDouble(RefundProductEnum.NUM.getAttr()));
            }
            productData.put(OutstockEnum.PRODUCT.getAttr(),jsonArray);
//            //TODO 单价
//            Map<String,Object> map = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
//            map.put("corpid",corpid);
//            map.put("del",0);
//            map.put("contractId",contractId);
//            List<ContractProductEntity> contractProductEntityList = contractProductModel.findEntitys(map);
        }else {
            List<ContractProductEntity> contractProductEntityList = formDataValidateProductHelp.searchContractUnRefund(corpid,contractId,false, null);
            contractService.formatProduct4Show3(contractProductEntityList,productData,UpdateDataTypeEnum.LINK_ADD);
        }
        return isOpenJxc ? OutstockEnum.PRODUCT.getAttr() : ContractEnum.PRODUCT.getAttr();
    }

    @Override
    public RefundUpdateBatchVO updateBatch(RefundUpdateBatchDTO refundUpdateBatchDTO) throws XbbException {
        RefundUpdateBatchVO refundUpdateBatchVO = new RefundUpdateBatchVO();
        try {
            String corpid = refundUpdateBatchDTO.getCorpid();
            List<UpdateDataEntity> updateList = new ArrayList<>();
            List<RefundUpdateDTO> contractUpdateList = refundUpdateBatchDTO.getRefundUpdateList();
            if (Objects.nonNull(contractUpdateList) && !contractUpdateList.isEmpty()) {
                contractUpdateList.forEach((item)->{
                    updateList.add(ExplainUtil.getUpdateData(item.getId(), item.getData(), corpid));
                });
            }
            if (!updateList.isEmpty()) {
                refundModel.updateBatch(updateList, corpid);
            }
        } catch (Exception e) {
            LOG.error("refundServiceImpl.updateBatch 执行出错：", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
        return refundUpdateBatchVO;
    }

    @Override
    public RefundUpdateBatchVO updateBatchImmediately(RefundUpdateBatchDTO refundUpdateBatchDTO) throws XbbException {
        RefundUpdateBatchVO refundUpdateBatchVO = new RefundUpdateBatchVO();
        try {
            String corpid = refundUpdateBatchDTO.getCorpid();
            List<UpdateDataEntity> updateList = new ArrayList<>();
            List<RefundUpdateDTO> contractUpdateList = refundUpdateBatchDTO.getRefundUpdateList();
            if (Objects.nonNull(contractUpdateList) && !contractUpdateList.isEmpty()) {
                contractUpdateList.forEach((item)->{
                    updateList.add(ExplainUtil.getUpdateData(item.getId(), item.getData(), corpid));
                });
            }
            if (!updateList.isEmpty()) {
                refundModel.updateBatchImmediately(updateList, corpid);
            }
        } catch (Exception e) {
            LOG.error("refundServiceImpl.updateBatch 执行出错：", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
        return refundUpdateBatchVO;
    }

    /**
     * 获取合同之前关联的退货退款的退款金额
     * @param corpid
     * @param contractId
     * @return
     * @throws XbbException
     */
    @Override
    public Double getRefundReturnAmount(String corpid, Long contractId) throws XbbException{
        Map<String, Object> params = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        params.put(ParameterConstant.CORPID, corpid);
        params.put(ParameterConstant.DEL, DelEnum.NORMAL.getDel());
        List<PaasFormDataEntityExt> refundEntityExts = paasEsModel.selectByOneCondition(RedundantTemplateTypeEnum.REFUND.getCode(),
                RefundEnum.CONTRACT_ID.getAttr(), contractId, params, IndexTypeEnum.IDX_SAAS_REFUND);
        Double refundReturnAmount = BasicConstant.ZERO_DOUBLE;
        for (PaasFormDataEntityExt refund : refundEntityExts) {
            JSONObject refundData = refund.getData();
            if(refundData == null){
                break;
            }
            Double returnAmount = getDoubleOrDefaultFromFormData(refundData, RefundEnum.RETURN_AMOUNT.getAttr(), BasicConstant.ZERO_DOUBLE);
            refundReturnAmount = Arith.add(refundReturnAmount, returnAmount);
        }
        return refundReturnAmount;
    }

    @Override
    public boolean judgeRefundAllInBound(Long instockId, Long refundId, String corpid, List<ProductSavePojo> productSavePojoList) throws XbbException {
        return refundSaveHelp.judgeRefundAllInBound(instockId, refundId, corpid, productSavePojoList);
    }

    @Override
    public PagingProductVO getPagingProduct(PagingProductDTO pagingProductDTO) throws XbbException {
        PagingProductVO pagingProductVO = new PagingProductVO();
        Map<String, Object> modelMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        modelMap.put(ParameterConstant.CORPID, pagingProductDTO.getCorpid());
        modelMap.put(ParameterConstant.CONTRACT_ID, pagingProductDTO.getDataId());
        modelMap.put(ParameterConstant.DEL, DelEnum.NORMAL.getDel());
        modelMap.put(ParameterConstant.PAGE,  pagingProductDTO.getPage());
        modelMap.put(ParameterConstant.ORDER_BY_STR, BasicConstant.SORT);
        PageHelper pageHelper = PageHelperUtil.getPageHelper(modelMap, contractProductModel, pagingProductDTO.getPageSize());
        List<ContractProductEntity> contractProductList = (List<ContractProductEntity>) PageHelperUtil.getEntityList(modelMap, pageHelper, contractProductModel);
        if (pagingProductDTO.getUpdateDataTypeEnum().isDetail()) {
            DetailProductVO detailProductVO = formatProduct4DetailShow(contractProductList, pagingProductDTO);
            pagingProductVO.setProductDataArr(detailProductVO.getProductDataArr());
        }
        pagingProductVO.setPageHelper(pageHelper);
        return pagingProductVO;
    }

    @Override
    public ChangeDocumentStatusSaveVO changeDocumentStatus(ChangeDocumentStatusSaveDTO changeDocumentStatusSaveDTO) throws XbbException {
        ChangeDocumentStatusSaveVO changeDocumentStatusSaveVO = new ChangeDocumentStatusSaveVO();
        try {
            Boolean isOpen = changeDocumentStatusSaveDTO.getIsOpen();
            String corpid = changeDocumentStatusSaveDTO.getCorpid();
            Long refundId = changeDocumentStatusSaveDTO.getDataId();
            Integer businessType = changeDocumentStatusSaveDTO.getBusinessType();
            RefundEntityExt refundEntityExt = refundModel.getByKey(refundId, corpid);
            if (Objects.isNull(refundEntityExt)) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100028, MessageConstant.FORM_DATA_NOT_EXIST);
            }
            JSONObject refundData = refundEntityExt.getData();
            //如果是开启退货退款
            if (isOpen) {
                Integer allInBound = refundData.getInteger(RefundEnum.ALL_IN_BOUND.getAttr());
                //如果全部入库则直接发货设置成全部入库
                if (Objects.equals(allInBound, AllInBoundEnum.ALL_IN.getCode())) {
                    refundData.put(RefundEnum.REFUND_STATUS.getAttr(), RefundStatusEnum.REFUND.getCode());
                }else {
                    SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
                    BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
                    boolQueryBuilder.filter(termQuery("corpid.keyword",corpid));
                    boolQueryBuilder.filter(termQuery(InstockEnum.getEsAttr4Keyword(InstockEnum.TYPE), InstockTypeEnum.RED_CONTRACT_INSTOCK.getCode()));
                    boolQueryBuilder.filter(termQuery(InstockEnum.getEsAttr4Keyword(InstockEnum.REF_ID), refundId));
                    boolQueryBuilder.filter(termQuery(StringConstant.DEL,DelEnum.NORMAL.getDel()));
                    boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, IndexTypeEnum.IDX_SAAS_INSTOCK.getType()));
                    sourceBuilder.query(boolQueryBuilder);
                    PageRequest pageRequest = EsUtil.setPage(sourceBuilder, 1, 1);
                    SearchRequest searchRequest = new SearchRequest(IndexTypeEnum.IDX_SAAS_INSTOCK.getIndex());
                    searchRequest.source(sourceBuilder);
                    XbbAggregatedPage<PaasFormDataEntityExt> entities = xbbElasticsearchRestTemplate.queryForPages(pageRequest,searchRequest, PaasFormDataEntityExt.class);

                    if (entities.getTotalElements() < 1){
                        refundData.put(RefundEnum.REFUND_STATUS.getAttr(), RefundStatusEnum.UNREFUND.getCode());
                    }else {
                        refundData.put(RefundEnum.REFUND_STATUS.getAttr(), RefundStatusEnum.PARTIAL.getCode());
                    }
                }
            }else {
                refundData.put(RefundEnum.REFUND_STATUS.getAttr(), RefundStatusEnum.CLOSED.getCode());
            }
            refundModel.update(refundEntityExt);
            //添加关闭和开启退货退款的按钮
            String refundStatus = FastJsonHelper.getStringOrDefaultFromFormData(refundData, RefundEnum.REFUND_STATUS.getAttr(), RefundStatusEnum.UNREFUND.getCode());
            //如果全部出库，则没有开启关闭按钮
            if (!Objects.equals(refundStatus, RefundStatusEnum.REFUND.getCode())) {
                ButtonPojo buttonPojo = new ButtonPojo();
                if (Objects.equals(refundStatus,RefundStatusEnum.CLOSED.getCode())&&changeDocumentStatusSaveDTO.getLoginUser().getPermSet().contains(EnableButtonEnum.REFUND_ENABLE.getPermission())) {
                    buttonPojo.setAttr("refund");
                    buttonPojo.setValue(OperateTypeEnum.ENABLE.getName());
                    buttonPojo.setLinkBusinessType(XbbRefTypeEnum.REFUND.getCode());
                    List<ButtonPojo> topRightButton = new ArrayList<>();
                    topRightButton.add(buttonPojo);
                    changeDocumentStatusSaveVO.setTopRightButton(topRightButton);
                }else if (!Objects.equals(refundStatus,RefundStatusEnum.CLOSED.getCode())&&changeDocumentStatusSaveDTO.getLoginUser().getPermSet().contains(EnableButtonEnum.REFUND_UNABLE.getPermission())){
                    buttonPojo.setAttr("refund");
                    buttonPojo.setValue(OperateTypeEnum.UNABLE.getName());
                    buttonPojo.setLinkBusinessType(XbbRefTypeEnum.REFUND.getCode());
                    List<ButtonPojo> topRightButton = new ArrayList<>();
                    topRightButton.add(buttonPojo);
                    changeDocumentStatusSaveVO.setTopRightButton(topRightButton);
                }
            }
            // 刷新页面saas关联新建工作流
            PaasFormDataEntityExt paasFormDataEntityExt = new PaasFormDataEntityExt();
            BeanUtil.copyProperties(refundEntityExt,paasFormDataEntityExt);
            if (Objects.equals(PlatFormEnum.DINGTALK.getValue(), changeDocumentStatusSaveDTO.getPlatform())) {
                // 设置移动端详情右上角操作
                FormDataGetVO formDataGetVO = new FormDataGetVO();
                mobileDetailService.handelMobileWorkFlow(changeDocumentStatusSaveDTO.getLoginUser(), businessType, formDataGetVO, paasFormDataEntityExt);
                changeDocumentStatusSaveVO.setTopPermissions(formDataGetVO.getTopPermissions());
            }else {
                List<WorkFlowPojo> workFlowPojoList = new ArrayList<>();
                proDetailHandlerHelp.handelDetailWorkFlow(businessType, paasFormDataEntityExt, workFlowPojoList, changeDocumentStatusSaveDTO.getLoginUser());
                changeDocumentStatusSaveVO.setWorkFlowPojoList(workFlowPojoList);
            }
        } catch (Exception e) {
            LOG.error("refundServiceImpl.changeDocumentStatus 执行出错：", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
        return changeDocumentStatusSaveVO;
    }

    @Override
    public void updateBatchLabelAttr(AddLabelDTO addLabelDTO, List<PaasFormDataEntityExt> addBatchList, Boolean addOrDelete) throws XbbException {
        RefundUpdateBatchDTO refundUpdateBatchDTO = new RefundUpdateBatchDTO();
        BeanUtil.copyProperties(addLabelDTO, refundUpdateBatchDTO);
        List<RefundUpdateDTO> refundList = new ArrayList<>();
        addBatchList.forEach(item->{
            RefundUpdateDTO refundUpdateDTO = new RefundUpdateDTO();
            refundUpdateDTO.setData(item.getData());
            refundUpdateDTO.setId(item.getId());
            refundList.add(refundUpdateDTO);
        });
        refundUpdateBatchDTO.setRefundUpdateList(refundList);
        updateBatch(refundUpdateBatchDTO);

    }

    @Override
    public void  afterSaveForWorkflow(SaasFormSaveDTO saasFormSaveDTO, AssociatedBusinessAfterSavePojo associatedBusinessAfterSavePojo) throws XbbException {
        // 团队保存
        teamDataHelp.saveUserTeam(saasFormSaveDTO.getSaasNeedRedundantAttrPoJo(), saasFormSaveDTO.getNewPaasFormDataEntity().getId(), saasFormSaveDTO.getNewPaasFormDataEntity(), saasFormSaveDTO.getIsImport(), true);
//        userTeamService.saveUserTeam(saasFormSaveDTO);
    }

    @Override
    public void afterSaveForUpdateWorkflow(SaasFormSaveDTO saasFormSaveDTO, AssociatedBusinessAfterSavePojo associatedBusinessAfterSavePojo) throws XbbException {
        // 团队保存
        teamDataHelp.saveUserTeam(saasFormSaveDTO.getSaasNeedRedundantAttrPoJo(), saasFormSaveDTO.getNewPaasFormDataEntity().getId(), saasFormSaveDTO.getNewPaasFormDataEntity(), saasFormSaveDTO.getIsImport(), true);

    }

    public DetailProductVO formatProduct4DetailShow(List<ContractProductEntity> contractProductList, PagingProductDTO pagingProductDTO) throws XbbException{
        DetailProductVO detailProductVO = new DetailProductVO();
        JSONArray productArray = new JSONArray();
        for (ContractProductEntity contractProductEntity : contractProductList) {
            JSONObject json = new JSONObject();
            Double rate = 1D;
            if (Objects.nonNull(contractProductEntity.getData())) {
                json = contractProductEntity.getData();
            }
            if (Objects.nonNull(contractProductEntity.getBusinessUnit())) {
                contractProductEntity.setProductNum(Arith.div(contractProductEntity.getProductNum(), contractProductEntity.getRate()));
                contractProductEntity.setProductUnit(contractProductEntity.getBusinessUnit().toString());
                JSONObject priceData = contractProductEntity.getPriceData();
                rate = contractProductEntity.getRate();
                if (Objects.nonNull(priceData) && !priceData.isEmpty()) {
                    contractProductEntity.setPrice(priceData.getDouble(RefundProductEnum.PRICE.getAttr()));
                }
            }
            for (RefundProductEnum refundProductEnum : RefundProductEnum.values()) {
                if (!UpdateDataTypeEnum.DETAIL.formatShow(refundProductEnum.getShowType())) {
                    continue;
                }
                String attr = refundProductEnum.getAttr();
                switch (refundProductEnum) {
                    case PRODUCT:
                        json.put(attr, contractProductEntity.getProductId());
                        break;
                    case PRICE:
                        json.put(attr, contractProductEntity.getPrice());
                        break;
                    case NUM:
                        json.put(attr, - contractProductEntity.getProductNum());
                        break;
                    case SUBTOTAL:
                        json.put(attr, Arith.mul(contractProductEntity.getPrice(), - contractProductEntity.getProductNum()));
                        break;
                    case MEMO:
                        json.put(attr, contractProductEntity.getMemo());
                        break;
                    case UNIT:
                        json.put(attr, contractProductEntity.getProductUnit());
                        break;
                    case INSTOCK_NUM:
                        json.put(attr, Arith.div(contractProductEntity.getInstockNum(), rate));
                        break;
                    case WAIT_INSTOCK_NUM:
                        json.put(attr,Arith.sub(Math.abs(contractProductEntity.getProductNum()), Arith.div(contractProductEntity.getInstockNum(), rate)));
                        break;
                    case REFUND_STATUS:
                        if (contractProductEntity.getInstockNum() > 0) {
                            if (Double.compare(Math.abs(contractProductEntity.getProductNum()), Arith.div(contractProductEntity.getInstockNum(), rate)) <= 0) {
                                json.put(attr, I18nMessageUtil.getMessage(I18nStringConstant.STOCK_IN_ALL));
                            } else {
                                json.put(attr, I18nMessageUtil.getMessage(I18nStringConstant.PARTIAL_WAREHOUSING));
                            }
                        } else {
                            json.put(attr, InOutStockStatusEnum.UN_INSTOCK.getName());
                        }
                        break;
                    default:
                        break;
                }
            }
            if (Objects.equals(json.getDouble(SelectProductEnum.GUARANTEE_PERIOD.getAttr()), 0D)) {
                if (Objects.equals(json.getLong(SelectProductEnum.PRODUCE_DATE.getAttr()), 0L) || Objects.isNull(json.get(SelectProductEnum.PRODUCE_DATE.getAttr()))) {
                    json.remove(SelectProductEnum.GUARANTEE_PERIOD.getAttr());
                }
            }
            json.put(BusinessConstant.PRODUCT_SUB_ID, contractProductEntity.getId());
            json.put(BusinessConstant.PARENT_ID, contractProductEntity.getParentId());
            productArray.add(json);
        }
        detailProductVO.setProductDataArr(productArray);
        return detailProductVO;
    }

    @Override
    public void formatProduct4Show2(Long dataId, String corpid, JSONObject data, UpdateDataTypeEnum updateDataTypeEnum) throws XbbException {
        refundModel.formatProduct4Show2(dataId, corpid, data, updateDataTypeEnum);
    }

    @Override
    public void updateBatchByBusinessRule(RefundUpdateByBusinessRuleDTO refundUpdateByBusinessRuleDTO) throws XbbException {
        try {
            String corpid = refundUpdateByBusinessRuleDTO.getCorpid();
            List<PaasFormDataEntityExt> formDataList = refundUpdateByBusinessRuleDTO.getFormDataList();
            List<UpdateDataEntity> updateList = ExplainUtil.getUpdateValueByBusinessRule(formDataList, corpid, refundUpdateByBusinessRuleDTO.getOperations());

            if (!updateList.isEmpty()) {
                refundModel.updateBatch(updateList, corpid);
                RuleBusinessLogDTO businessLogDTO = new RuleBusinessLogDTO();
                BeanUtil.copyProperties(refundUpdateByBusinessRuleDTO, businessLogDTO);
                businessLogDTO.setFormDataList(formDataList);
                ruleBusinessLogger.writeLog(businessLogDTO, updateList);
            }
        } catch (Exception e) {
            LOG.error("refundService.updateFormDataByBusinessRule根据业务规则更新数据出错：", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }
    }

    @Override
    public ProductSummaryVO summaryProductList(BusinessProductListDTO businessProductListDTO) throws XbbException {
        ProductSummaryVO businessProductListVO = new ProductSummaryVO();
        Double num = 0D;
        Integer size = 0;

        String corpid = businessProductListDTO.getCorpid();
        Long refundId = businessProductListDTO.getDataId();
        RefundEntityExt refundEntityExt = refundModel.getByKey(refundId, corpid);
        if (refundEntityExt == null || Objects.equals(refundEntityExt.getDel(), DelEnum.DELETE.getDel())) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100404);
        }

        Long contractId = FastJsonHelper.getLongOrDefaultFromFormData(refundEntityExt.getData(), RefundEnum.RED_CONTRACT_ID.getAttr(), 0L);

        /*// jxc开启时:查询退货出库产品  jxc关闭时:查询退货合同产品
        boolean isOpenJxc = ifJXCOpen(corpid);
        // 查询出库产品
        if (isOpenJxc) {
            ContractEntityExt contract = contractModel.getByKey(contractId, corpid);
            if (Objects.isNull(contract)) {
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001.getCode(), MessageConstant.FORM_DATA_NOT_EXIST);
            }
            JSONObject contractData = contract.getData();
            if (Objects.isNull(contractData)) {
                throw new XbbException(ContractErrorCodeEnum.API_ERROR_203001);
            }
            JSONArray outstoArray = contractData.getJSONArray(ContractEnum.OUTSTOCK_ID.getAttr());
            List<Long> outstockIds = new ArrayList<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            if (outstoArray != null) {
                outstockIds = outstoArray.toJavaList(Long.class);
            }
            Map<String, Object> outModelMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            outModelMap.put(ParameterConstant.CORPID, corpid);
            outModelMap.put("outstockIdIn", outstockIds);
            outModelMap.put(ParameterConstant.DEL, DelEnum.NORMAL.getDel());
            outModelMap.put(ParameterConstant.COLUMNS, "product_num");
            List<OutstockProductEntity> outstockProductList = outstockProductModel.findEntitys(outModelMap);
            for (OutstockProductEntity entity : outstockProductList) {
                Double productNum = entity.getProductNum() != null ? entity.getProductNum(): 0D;
                num = Arith.add(num, productNum);
            }
            size = outstockProductList.size();
        } else {
            Map<String, Object> modelMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
            modelMap.put(ParameterConstant.CORPID, corpid);
            modelMap.put("contractId", contractId);
            modelMap.put(ParameterConstant.DEL, DelEnum.NORMAL.getDel());
            modelMap.put(ParameterConstant.COLUMNS, "product_num");
            List<ContractProductEntity> contractProductList = contractProductModel.findEntitys(modelMap);
            for (ContractProductEntity entity : contractProductList) {
                Double productNum = entity.getProductNum() != null ? Math.abs(entity.getProductNum()): 0D;
                num = Arith.add(num, productNum);
            }
            size = contractProductList.size();
        }*/

        Map<String, Object> modelMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        modelMap.put(ParameterConstant.CORPID, corpid);
        modelMap.put("contractId", contractId);
        modelMap.put(ParameterConstant.DEL, DelEnum.NORMAL.getDel());
        modelMap.put(ParameterConstant.COLUMNS, "product_num, price,business_num");
        List<ContractProductEntity> contractProductList = contractProductModel.findEntitys(modelMap);
        Double count = 0D;
        for (ContractProductEntity entity : contractProductList) {
            Double productNum = entity.getProductNum() != null ? Math.abs(entity.getProductNum()): 0D;
            Double price = entity.getPrice() == null ? 0D : entity.getPrice();
            count = Arith.add(count, Arith.mul(productNum, price));
            num = Arith.add(num, entity.getBusinessNum() == null ? productNum : entity.getBusinessNum());
        }
        size = contractProductList.size();

        String summaryInfo = String.format(I18nMessageUtil.getMessage(StringConstant.PRODUCTS_TYPE_NUM), size, Arith.doubleToBigDecimal(num));
        businessProductListVO.setSummaryInfo(summaryInfo);
        businessProductListVO.setMoneyInfo(String.format(I18nMessageUtil.getMessage(StringConstant.PRODUCTS_MONEY_COUNT), "", count));
        Boolean isJxcUse = paasAppService.validateAppEnable(null, XbbRefTypeEnum.JXC.getAlias(), SaasMarkEnum.SAAS.getCode(), corpid);
        if (isJxcUse) {
            //添加关闭和开启退货退款的按钮
            JSONObject data = refundEntityExt.getData();
            String refundStatus = FastJsonHelper.getStringOrDefaultFromFormData(data, RefundEnum.REFUND_STATUS.getAttr(), RefundStatusEnum.UNREFUND.getCode());
            if (!Objects.equals(refundStatus, RefundStatusEnum.REFUND.getCode()) && num != 0D) {
                ButtonPojo buttonPojo = new ButtonPojo();
                if (Objects.equals(refundStatus, RefundStatusEnum.CLOSED.getCode()) && businessProductListDTO.getLoginUser().getPermSet().contains(EnableButtonEnum.REFUND_ENABLE.getPermission())) {
                    buttonPojo.setAttr("refund");
                    buttonPojo.setValue(OperateTypeEnum.ENABLE.getName());
                    buttonPojo.setLinkBusinessType(XbbRefTypeEnum.REFUND.getCode());
                    List<ButtonPojo> topRightButton = new ArrayList<>();
                    topRightButton.add(buttonPojo);
                    businessProductListVO.setTopRightButton(topRightButton);
                }else if (!Objects.equals(refundStatus, RefundStatusEnum.CLOSED.getCode()) && businessProductListDTO.getLoginUser().getPermSet().contains(EnableButtonEnum.REFUND_UNABLE.getPermission())){
                    buttonPojo.setAttr("refund");
                    buttonPojo.setValue(OperateTypeEnum.UNABLE.getName());
                    buttonPojo.setLinkBusinessType(XbbRefTypeEnum.REFUND.getCode());
                    List<ButtonPojo> topRightButton = new ArrayList<>();
                    topRightButton.add(buttonPojo);
                    businessProductListVO.setTopRightButton(topRightButton);
                }
            }
        }
        return businessProductListVO;
    }

    /**
     * 退货退款中关联新建红冲发票 金额明细数据格式组装
     * (发票格式重构,传输格式已统一不需要再转格式了,可以废弃)
     * @param jsonObject 红冲发票信息
     * @throws XbbException error
     * @author zhouwq
     * @date 2019/12/3 15:35
     */
    private void invoiceAmountDetailHandle(JSONObject jsonObject) throws XbbException {
        /*JSONArray amountDetailResult = new JSONArray();
        JSONArray array = jsonObject.getJSONArray(PaasConstant.AMOUNTDETAIL);
        if (!array.isEmpty()) {
            for (Object object : array) {
                //拷贝一份原发票所有内容信息
                JSONObject amountDetailAll = (JSONObject) jsonObject.clone();
                //金额明细
                JSONObject relationObj = (JSONObject) object;
                RelationshipGetPojo relationshipGetPojo = JSONObject.parseObject(relationObj.toJSONString(), RelationshipGetPojo.class);
                if (relationshipGetPojo.getContractId() != null && relationshipGetPojo.getContractId() != 0L) {
                    JSONArray contractArray = new JSONArray();
                    JSONObject contractObject = new JSONObject();
                    contractObject.put(StringConstant.SAAS_LINK_BUSINESS_ID, relationshipGetPojo.getContractId());
                    contractObject.put(StringConstant.SAAS_LINK_BUSINESS_NAME, relationshipGetPojo.getContractNo());
                    contractObject.put(ContractEnum.AMOUNT.getAttr(), relationshipGetPojo.getContractAmount());
                    contractArray.add(contractObject);
                    amountDetailAll.put(InvoiceEnum.CONTRACT_ID.getAttr(), contractArray);
                }
                if (relationshipGetPojo.getPaymentId() != null && relationshipGetPojo.getPaymentId() != 0L) {
                    JSONArray paymentArray = new JSONArray();
                    JSONObject paymentObject = new JSONObject();
                    paymentObject.put(StringConstant.SAAS_LINK_BUSINESS_ID, relationshipGetPojo.getPaymentId());
                    paymentObject.put(StringConstant.SAAS_LINK_BUSINESS_NAME, relationshipGetPojo.getPaymentNo());
                    paymentObject.put(PaymentEnum.AMOUNT.getAttr(), relationshipGetPojo.getPaymentAmount());
                    paymentArray.add(paymentObject);
                    amountDetailAll.put(InvoiceEnum.PAYMENT_ID.getAttr(), paymentArray);
                }
                if (relationshipGetPojo.getPaymentSheetId() != null && relationshipGetPojo.getPaymentSheetId() != 0L) {
                    JSONArray paymentSheetArray = new JSONArray();
                    JSONObject paymentSheetObject = new JSONObject();
                    paymentSheetObject.put(StringConstant.SAAS_LINK_BUSINESS_ID, relationshipGetPojo.getPaymentSheetId());
                    paymentSheetObject.put(StringConstant.SAAS_LINK_BUSINESS_NAME, relationshipGetPojo.getPaymentSheetNo());
                    paymentSheetObject.put(PaymentSheetEnum.AMOUNT.getAttr(), relationshipGetPojo.getPaymentSheetAmount());
                    paymentSheetArray.add(paymentSheetObject);
                    amountDetailAll.put(InvoiceEnum.PAYMENT_SHEET_ID.getAttr(), paymentSheetArray);
                }
                Double invoiceAmount = 0D;
                if (relationshipGetPojo.getContractInvoiceAmount() != null) {
                    invoiceAmount = relationshipGetPojo.getContractInvoiceAmount();
                } else if (relationshipGetPojo.getPaymentInvoiceAmount() != null) {
                    invoiceAmount = relationshipGetPojo.getPaymentInvoiceAmount();
                } else if (relationshipGetPojo.getPaymentSheetInvoiceAmount() != null) {
                    invoiceAmount = relationshipGetPojo.getPaymentSheetInvoiceAmount();
                } else {
                    return;
                }
                amountDetailAll.put(InvoiceEnum.TOTAL_MONEY.getAttr(), invoiceAmount);

                amountDetailResult.add(amountDetailAll);
            }
        }
        jsonObject.put(PaasConstant.AMOUNTDETAIL, amountDetailResult);*/
    }

    /**
     * 处理web端关联新建红冲回款单数据组装
     * @param paymentJsonObject web端返回新建回款单信息
     * @return com.xbongbong.paas.domain.entity.ext.PaasFormDataEntityExt
     * @return 回款单实体
     * @author zhouwq
     * @date 2019/12/6 15:17
     * @version v1.0 资金3.0 由PaymentSheetEntityExt改为父类PaasFormDataEntityExt
     */
    private PaasFormDataEntityExt handlePaymentSheetWebPlatformLinkAddData(JSONObject paymentJsonObject){
        PaasFormDataEntityExt entityExt = new PaasFormDataEntityExt();
        if (paymentJsonObject == null) {
            return entityExt;
        }
        entityExt.setSerialNo(paymentJsonObject.getString(PaymentSheetEnum.SHEET_NO.getAttr()));
        entityExt.setId(paymentJsonObject.getLong(StringConstant.SAAS_LINK_BUSINESS_ID));
        entityExt.setDataId(paymentJsonObject.getLong(StringConstant.DATA_ID));
        entityExt.setFormId(paymentJsonObject.getLong("formId"));
        entityExt.setMenuId(paymentJsonObject.getLong("menuId"));
        entityExt.setAppId(paymentJsonObject.getLong("appId"));
        entityExt.setAlone(paymentJsonObject.getInteger(FieldTypeEnum.SHEET_ALONE.getAlias()));
        entityExt.setUuid(paymentJsonObject.getString(FieldTypeEnum.SHEET_UUID.getAlias()));
        entityExt.setAddTime(paymentJsonObject.getLong("addTime"));
        entityExt.setUpdateTime(paymentJsonObject.getLong("updateTime"));
        entityExt.setOwnerId(paymentJsonObject.getString("ownerId"));
        entityExt.setFlowStatus(paymentJsonObject.getInteger("flowStatus"));
        entityExt.setDepartmentId(0L);
        entityExt.setDel(paymentJsonObject.getInteger("del"));
        entityExt.setCreatorId(paymentJsonObject.getString(StringConstant.CREATOR_ID));
        paymentJsonObject.remove("addTime");
        paymentJsonObject.remove("updateTime");
        paymentJsonObject.remove(PaymentSheetEnum.SHEET_NO.getAttr());
        entityExt.setData(paymentJsonObject);
        return entityExt;
    }

    /**
     * 处理web端关联新建发票数据组装
     * @param paymentJsonObject web端返回新建回款单信息
     * @return 回款单实体
     * @author zhouwq
     * @date 2019/12/6 15:17
     */
    private PaasFormDataEntity handleInvoiceWebPlatformLinkAddData(JSONObject paymentJsonObject){
        PaasFormDataEntity paasFormDataEntity = new PaymentSheetEntityExt();
        paasFormDataEntity.setSerialNo(paymentJsonObject.getString(PaymentSheetEnum.SHEET_NO.getAttr()));
        paasFormDataEntity.setId(paymentJsonObject.getLong(StringConstant.SAAS_LINK_BUSINESS_ID));
        paasFormDataEntity.setDataId(paymentJsonObject.getLong(StringConstant.DATA_ID));
        paasFormDataEntity.setFormId(paymentJsonObject.getLong("formId"));
        paasFormDataEntity.setMenuId(paymentJsonObject.getLong("menuId"));
        paasFormDataEntity.setAppId(paymentJsonObject.getLong("appId"));
        paasFormDataEntity.setAddTime(paymentJsonObject.getLong("addTime"));
        paasFormDataEntity.setUpdateTime(paymentJsonObject.getLong("updateTime"));
        paasFormDataEntity.setOwnerId(paymentJsonObject.getString("ownerId"));
        paasFormDataEntity.setFlowStatus(paymentJsonObject.getInteger("flowStatus"));
        paasFormDataEntity.setDepartmentId(0L);
        paasFormDataEntity.setDel(paymentJsonObject.getInteger("del"));
        paasFormDataEntity.setCreatorId(paymentJsonObject.getString("creatorId"));
        paymentJsonObject.remove("addTime");
        paymentJsonObject.remove("updateTime");
        paymentJsonObject.remove(PaymentSheetEnum.SHEET_NO.getAttr());
        paasFormDataEntity.setData(paymentJsonObject);
        return paasFormDataEntity;
    }


    /**
     * 更新退货退款中的发票ID
     * @param refundId 退货退款ID
     * @param paasFormDataEntity 发票实体
     * @param saasFormSaveDTO 入参
     * @throws XbbException error
     * @author zhouwq
     * @date 2019/12/19 11:17
     */
    @Override
    public void updateRefundInvoiceId(Long refundId, PaasFormDataEntity paasFormDataEntity, SaasFormSaveDTO saasFormSaveDTO) throws XbbException {
        String corpid = saasFormSaveDTO.getCorpid();
        RefundUpdateBatchDTO refundUpdateBatchDTO = new RefundUpdateBatchDTO();
        BeanUtil.copyProperties(saasFormSaveDTO, refundUpdateBatchDTO);
        List<RefundUpdateDTO> refundUpdateList = new ArrayList<>();
        RefundUpdateDTO refundUpdateDTO = new RefundUpdateDTO();
        refundUpdateDTO.setId(refundId);
        JSONObject newData = new JSONObject();
        RefundEntityExt refundEntityExt = refundModel.getByKey(refundId, corpid);
        JSONObject oldData = refundEntityExt.getData();
        JSONArray invoiceIds = FastJsonHelper.getJsonArrOrDefaultFromFormData(oldData, RefundEnum.INVOICES.getAttr(), new JSONArray());
        invoiceIds.add(paasFormDataEntity.getId());
        newData.put(RefundEnum.INVOICES.getAttr(), invoiceIds);
        JSONArray paymentSheetNames = FastJsonHelper.getJsonArrOrDefaultFromFormData(oldData, RefundEnum.INVOICES_LINKED_TEXT.getAttr(), new JSONArray());
        paymentSheetNames.add(paasFormDataEntity.getSerialNo());
        newData.put(RefundEnum.INVOICES_LINKED_TEXT.getAttr(), paymentSheetNames);
        refundUpdateDTO.setData(newData);
        refundUpdateList.add(refundUpdateDTO);
        refundUpdateBatchDTO.setRefundUpdateList(refundUpdateList);
        try{
            updateBatch(refundUpdateBatchDTO);
        } catch (XbbException e) {
            throw new XbbException(BuinessDefaultErrorCodeEnum.API_ERROR_200019);
        }
        Long now = DateTimeUtil.getInt();
        RefundInvoiceEntity refundInvoiceEntity = new RefundInvoiceEntity();
        refundInvoiceEntity.setRefundId(refundId);
        refundInvoiceEntity.setCorpid(corpid);
        refundInvoiceEntity.setDel(DelEnum.NORMAL.getDel());
        refundInvoiceEntity.setAddTime(now);
        refundInvoiceEntity.setUpdateTime(now);
        refundInvoiceEntity.setInvoiceId(paasFormDataEntity.getId());
        refundInvoiceEntity.setRedContractId(0L);
        refundInvoiceEntity.setRedPaymentId(0L);
        refundInvoiceEntity.setFlowStatus(FlowStatusEnum.NOT_NEED_APPROVAL.getType());
        refundInvoiceModel.save(refundInvoiceEntity);

    }

    @Override
    public void updateRefund4Del(String corpid, List<Long> delIdList, Map<Long, Double> sheetIdToAmount) throws XbbException {
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        boolQueryBuilder.filter(termQuery("corpid.keyword", corpid));
        boolQueryBuilder.filter(termsQuery("data." + RefundEnum.PAYMENT_SHEETS.getAttr() + ".keyword", delIdList));
        boolQueryBuilder.filter(termQuery("del", 0));
        boolQueryBuilder.filter(termsQuery("flowStatus",Arrays.asList(FlowStatusEnum.NOT_NEED_APPROVAL.getType(), FlowStatusEnum.PASS.getType())));
        boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, IndexTypeEnum.IDX_SAAS_REFUND.getType()));
        //字段过滤
        String refundAmountStr = StringConstant.JSON_DATA + StringConstant.POINT + RefundEnum.REFUND_AMOUNT.getAttr();
        String refundPaymentSheetStr = StringConstant.JSON_DATA + StringConstant.POINT + RefundEnum.PAYMENT_SHEETS.getAttr();
        sourceBuilder.fetchSource(new String[]{StringConstant.SAAS_LINK_BUSINESS_ID, refundAmountStr, refundPaymentSheetStr}, null);
        sourceBuilder.query(boolQueryBuilder);
        SearchRequest searchRequest = new SearchRequest(IndexTypeEnum.IDX_SAAS_REFUND.getIndex());
        PageRequest pageRequest = EsUtil.setPage(sourceBuilder, BasicConstant.ONE, SizeConstant.PAGE_SIZE);
        searchRequest.source(sourceBuilder);
        XbbAggregatedPage<PaasFormDataEntityExt> esEntities = xbbElasticsearchRestTemplate.queryForPages(pageRequest, searchRequest, PaasFormDataEntityExt.class);
        List<PaasFormDataEntityExt> result = esEntities.getContent();
        if (result.size() > 0) {
            updateRefundAmountByIds(corpid, result, sheetIdToAmount);
        }

    }

    /**
     * 删除红冲回款单时更新退货退款中合计退款金额
     * @param corpid 公司ID
     * @param refundList 退货退款集合
     * @param paymentSheetIdToAmount 回款单对应的回款金额
     * @throws XbbException error
     * @author zhouwq
     * @date 2019/12/20 15:53
     */
    private void updateRefundAmountByIds(String corpid, List<PaasFormDataEntityExt> refundList, Map<Long, Double> paymentSheetIdToAmount) throws XbbException {
        RefundUpdateBatchDTO refundUpdateBatchDTO = new RefundUpdateBatchDTO();
        refundUpdateBatchDTO.setCorpid(corpid);
        List<RefundUpdateDTO> refundUpdateList = new ArrayList<>();
        for (PaasFormDataEntityExt paasFormDataEntityExt : refundList){
            RefundUpdateDTO refundUpdateDTO = new RefundUpdateDTO();
            refundUpdateDTO.setId(paasFormDataEntityExt.getId());
            JSONObject newData = new JSONObject();
            JSONObject oldData = paasFormDataEntityExt.getData();
            Double oldRefundAmount = getDoubleOrDefaultFromFormData(oldData, RefundEnum.REFUND_AMOUNT.getAttr(), 0D);
            JSONArray paymentSheetIds = FastJsonHelper.getJsonArrOrDefaultFromFormData(oldData, RefundEnum.PAYMENT_SHEETS.getAttr(), new JSONArray());
            Double paymentSheetRefundAmount = 0D;
            for(Object paymentSheetObj : paymentSheetIds) {
                Long paymentSheetId = Long.valueOf(paymentSheetObj.toString());
                Double paymentAmount = paymentSheetIdToAmount.get(paymentSheetId);
                if (paymentAmount != null) {
                    paymentSheetRefundAmount = Arith.add(paymentSheetRefundAmount, paymentAmount);
                }
            }
            //红冲金额为负
            double newRefundAmount = oldRefundAmount + paymentSheetRefundAmount;
            if (newRefundAmount < 0) {
                throw new XbbException(RefundErrorCodeEnum.API_ERROR_215027);
            }
            newData.put(RefundEnum.REFUND_AMOUNT.getAttr(), newRefundAmount);
            refundUpdateDTO.setData(newData);
            refundUpdateList.add(refundUpdateDTO);
        }
        refundUpdateBatchDTO.setRefundUpdateList(refundUpdateList);
        try{
            updateBatch(refundUpdateBatchDTO);
        } catch (XbbException e) {
            throw new XbbException(BuinessDefaultErrorCodeEnum.API_ERROR_200019);
        }

    }

    @Override
    public void dataConsistencyUpdate(String corpid, Long dataId, String value, String attr, String linkAttr) throws XbbException {
        try {
            BoolQueryBuilder filter = boolQuery()
                    .filter(termQuery("corpid.keyword", corpid))
                    .filter(termQuery("del", 0))
                    .filter(termQuery("data." + attr + ".keyword", dataId));
            List<String> fieldList = new ArrayList<>();
            fieldList.add(FieldTypeEnum.DATAID.getAlias());
            List<PaasFormDataEntityExt> esEntities = esHelper.findByScroll(IndexTypeEnum.IDX_SAAS_REFUND, filter, PaasFormDataEntityExt.class, fieldList);
            Set<Long> ids = new HashSet<>();
            for (PaasFormDataEntityExt esEntity : esEntities) {
                ids.add(esEntity.getDataId());
            }
            Map<String, Object> params = new HashMap<>();
            params.put("corpid", corpid);
            params.put("idIn", ids);
            params.put("del", 0);
            List<RefundEntityExt> refundEntityExts = refundModel.findEntitys(params);
           if (Objects.nonNull(refundEntityExts) && !refundEntityExts.isEmpty()) {
               List<RefundUpdateDTO> refundUpdateDTOList = new ArrayList<>();
               for (RefundEntityExt entityExt : refundEntityExts) {
                   RefundUpdateDTO refundUpdateDTO = new RefundUpdateDTO();
                   refundUpdateDTO.setId(entityExt.getId());
                   JSONObject data = new JSONObject();
                   data.put(linkAttr, value);
                   refundUpdateDTO.setData(data);
                   refundUpdateDTOList.add(refundUpdateDTO);
               }
               RefundUpdateBatchDTO refundUpdateBatchDTO = new RefundUpdateBatchDTO();
               refundUpdateBatchDTO.setCorpid(corpid);
               refundUpdateBatchDTO.setRefundUpdateList(refundUpdateDTOList);
               updateBatch(refundUpdateBatchDTO);
           }
        } catch (Exception e) {
            LOG.error("com.xbongbong.saas.service.impl.RefundServiceImpl.dataConsistencyUpdate fail， corpid=" + corpid + " dataId=" + dataId + "  attr=" + attr + "  value=" + value, e);
        }
    }

    @Override
    public Map<Long,String> getRefundNameMap(List<Long> handoverIdSet, String corpid) throws XbbException {
        Map<Long,String> refundNameMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        if (handoverIdSet.isEmpty()){
            return refundNameMap;
        }
        BoolQueryBuilder boolQueryBuilder = boolQuery();
        boolQueryBuilder.filter(termQuery("corpid.keyword",corpid));
        boolQueryBuilder.filter(termsQuery(FieldTypeEnum.DATAID.getAlias(),handoverIdSet));
        boolQueryBuilder.filter(termQuery(ElasticConstant.MY_JOIN_FIELD, IndexTypeEnum.IDX_SAAS_REFUND.getType()));
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.query(boolQueryBuilder);
        PageRequest pageRequest = EsUtil.setPage(sourceBuilder, 1, handoverIdSet.size());
        SearchRequest searchRequest = new SearchRequest(IndexTypeEnum.IDX_SAAS_REFUND.getIndex());
        searchRequest.source(sourceBuilder);
        XbbAggregatedPage<PaasFormDataEntity> esEntities = xbbElasticsearchRestTemplate.queryForPages(pageRequest,searchRequest,PaasFormDataEntity.class);
        for (PaasFormDataEntity entity : esEntities.getContent()){
            refundNameMap.put(entity.getDataId(),entity.getData().getString(RefundEnum.REFUND_NAME.getAttr()));
        }
        return refundNameMap;
    }

    @Override
    public void formatBatchExplain(List<FieldAttrEntity> fieldAttrEntityList, String enable) {
        BatchSeqExplainHelp.getInstance().formatExplain4BatchAffectProductAttr(fieldAttrEntityList, enable, RefundEnum.PRODUCTS.getAttr());
    }

    @Override
    public void formatBatchOrSeqExplain(List<FieldAttrEntity> fieldAttrEntityList, String enable, String alias) {
        if (CompanyConfigEnum.ENABLE_BATCH_SHELF_MANAGEMENT.getAlias().equals(alias)) {
            formatBatchExplain(fieldAttrEntityList, enable);
        }
    }
}
